更实用的TypeScript指南:不墨迹的入门

1,760 阅读6分钟

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。

本系列旨在帮你用正确的方式打开TypeScript。

前言

TypeScript,是JavaScript的超集...每次看到TypeScript教程的时候,文章都会从它的背景,一直介绍相比JavaScript的种种好处,然后再抛出一大堆的TypeScript知识要点。

可到了最后,真正上手的时候,却又好像只学会了let name:string。而文章所述的知识点,其实在TypeScript 中文手册 中都可以找到,而且更加全面。

所以,相对于知识点的广撒网,不如来学习一下,TypeScript在实战中该怎么用,在什么时候用。

更实用的TypeScript指南系列,从不同的使用场景出发,学习不同的TS语法点。让你不仅了解TS,更会用TS🧐。

系列文章

更实用的TypeScript指南:不墨迹的入门 - 掘金 (juejin.cn)

更实用的TypeScript指南:从ES6的class到TS的装饰器 - 掘金 (juejin.cn)

一个故事带你了解TypeScript程序类型 - 掘金 (juejin.cn)

不墨迹的知识点简介

下文将会用尽量简短的篇幅,概括常用的知识点并给出使用样例(默认你是对TypeScript有大概的概念的)。

如果想进一步了解,每个标题都链接了官方网站的地址。

基础类型

boolean  //布尔number   //数字string   //字符串object //对象number[] string[] 等 数据类型[]  或  Array<number> Array<string> 等 Array<数据类型>   //数组any[] //不确定个数,不确定类型的数组,但是不好的地方是就没有实时的编译提示了any //任何类型unknown //任何类型的安全形式undefined null 
//默认情况下null和undefined是所有类型的子类型,但是如果想把其赋值给某个类型的变量,想要不报错首先要关闭严格模式
​
​
void //没有类型,如 function f:void () { ... } 无返回值
​
never //函数无法返回的类型。
//例如一个会抛出异常的函数 就可以写 function f(msg:string):never {throw new Error(msg)}
​
​
enum //枚举 
例:
enum Color {Red = 2, Green, Blue} 
let c: Color = Color.Green;
let d:string = Color[2]
console.log(c)
>> 3
console.log(d)
>> Redlet a:[string,number,boolean] = ['xxx',12,true]  
//元组  与数组不同的是可以存在不同类型,但是数据类型的位置和个数要一一对应
​
类型一|类型二   //联合类型,同时接受多种类型
​
(<string>str).length  或  (str as string).length //类型断言,断言某个变量是某种类型,以防止报错。 
//这个为例,断言str是string类型,所以在提前不知道str的类型的情况下,使用.length方法也不会报错

需要注意的是很多地方没有提到的unknow类型,他与any不同的是使用unknown可以保证类型安全,而any则直接不进行类型检查,相当于又回到了JavaScript🤣,所以我们可以在很多情况下都用unknown来代替any。

例如:

let b:unknown //当我们不知道类型的时候,先用unknown类型 
b = 'abc'
let l:number = (b as string).length //某种情况下,我们确定了类型则使用类型断言来确定类型
//如果不用类型断言则会出现错误,而一开始换成any则不会,这是unknown安全性的体现

更多内容可以参考 [译] 理解TypeScript 中 any 和 unknown

接口(interface)

你可以把接口理解为一个契约,遵守契约的类型都有必须根据接口做出规范。

基本用法(含常见点)

interface Iperson {
    readonly firstName: string //只读
    lastName: string
    sex?: string //?:表示可以没有
} 
function showFullName(person: Iperson) {
    return person.firstName + person.lastName // person.qq是没有的
}//这里的函数传入的参数,必须同时具备firstName,lastName两种属性,但是多具备其他属性则不做要求,在传进时会把多余的参数去掉
let q: object = {
    firstName:'xx',
    lastName:'x',
    qq:'123'
}
console.log(showFullName(q as Iperson)) //注意这里断言了q是Iperson型,不然会类型不一致
>> xxx

接口也可以是函数类型的接口

//定义一个函数的规范
interface SearchFunc {
    (source: string, subString: string): boolean;
}
  
let mySearch: SearchFunc = function(so: string, su: string) {
    let result = so.search(su);
    return result > -1;
}

同时接口可以定义类类型(没用过类的直接跳到 更实用的TypeScript指南:从ES6的class到TS的装饰器 ,让你知道一些类的简单用法)

//定义两个接口
interface Time {
    currentTime: Date;
    setTime(d: Date): void;
}
interface Name {
    name: string;
    setname(pname: string): void;
}
​
//类使用接口
class Clock implements Time, Name {
    name:string
    currentTime: Date
    other: string  //可以在类中多定义属性,只要包含所有接口特性就行
    setTime(d: Date) {
        this.currentTime = d;
    }
    setname(pname: string) {
        this.name = pname;
    }
    constructor(h?: number, m?: number) { } //构造函数类是接口不约束的 
}

接口也可以继承:

interface L {
    len: number;
}
interface S extends L {
    area: number;
}
let s = <S>{}; //注意这里使用是断言,也可以写成let s: S = ({} as S)。和泛型区分开
s.len = 10, s.area = 100

其他用法,我们遇到具体场景具体说明,这里如果一股脑排列出来反而会混乱。

类(class)

这里你只介绍类是什么和基本知识点,为了是先看懂,他的应用将在 更实用的TypeScript指南:从ES6的class到TS的装饰器 中根据具体使用场景说明。

class Animal {
    private name: string = 'daHuang';//私有
    move(distanceInMeters: number = 0) {
        console.log(`Animal moved ${distanceInMeters}m.`);
    }
}
//继承
class Dog extends Animal {
    bark() {
        console.log('Woof! Woof!');
    }
}
​
const dog = new Dog();
dog.bark();
>> Woof! Woof!
dog.move(10);
>> Animal moved 10m.
dog.name //报错:属性“name”为私有属性,只能在类“Animal”中访问。

函数(function)

函数声明

const add = function(x:number = 1,y?:number):number {
    if(y)   
        return x+y
    else
        return x
} 
//add函数参数必须是数字类型,返回值必须是数字类型,x默认是1,y可选

函数重载

根据传入不同的参数而返回不同的类型

function add(x:string,y:string):string
function add(x:number,y:number):number
function add(x,y) {
    if(typeof(x) === 'string')
    return 'the String'+x+y //字符串拼接
    else return x+y  //相加
}
​
add(1,2)//可以,符合第二种重载
add('hello','world')//符合第一种重载
add(1,'ss')//报错,不符合重载类型

泛型(generic)

泛型用来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。

function fun<T>(x: T,y:number): T {
    return x;
}//将类型设置成类似于变量的形式,这样以后再用的时候就可以根据不同的数据类型,使用不同的参数fun<string>('xx',12)//可以
fun<string>(123,12)//可以
fun<number>('ss',12)//报错

类型别名 type

type作用就是给类型起一个新名字,支持基本类型、联合类型、元组及其它任何你需要的手写类型

例子:

type test = number; //基本类型
let num: test = 10;
type userOjb = {name:string} // 对象
type getName = ()=>string  // 函数
type data = [number,string] // 元组
type numOrFun = Second | getName  // 联合类型

全文尽量简短快速的概括了TS的常用点,目的在于用最短的时间先了解ts,再学会如何去用。

接下来的文章,将会结合使用具体使用时,从一些成熟的TS框架(如Vue3-ts和nestjs)或者日常使用中来看看TS是怎么用的。(我一直秉持着想学会怎么用就看看别人怎么用的观点🤣)

对了,如果你喜欢这个系列,不妨关注我,一起学习,一起进步!