阅读 128

typescript使用指北

项目配置

项目配置主要要使用项目配置里的typescript版本,而非电脑全局版本. 避免版本不一样, 造成开发,编译产生的结果不一样. 配置方法:

1. 切换到`.ts`文件 2. 在vs code 地址栏下方, 点击 `Typescript:Version`扩展项, 然后点击`Use Workspace Version`选项. 或者在项目根目录.vscode文件中的setting.json文件中增加配置项: `typescript.tsdk: "node_modules/typescript/lib"` 复制代码

image.png

image.png

类型

集合类型

string, number, boolean, symbol, null, undefined, bigint

字面量类型

使用一个字面量作为类型. 比如this is string

TypeScript 支持是那种字面量类型: 字符串字面量类型, 数字字面量类型, 布尔字面量类型. 对应的字符串字面量, 数字字面量, 布尔字面量分别拥有与其值一辆的字面量类型.

let specifiedStr: 'this is string' = 'this is string' let specifiedNum: 1 = 1 let specifiedBoolan: false = false let str: string = 'this is string' specifiedStr = str; //ts(2322), 类型string不能赋值给类型this is string str = specifiedStr; // ok 复制代码

字面量类型是集合类型的子类型, 它是集合类型的一种更具体的表达.

使用let和const定义的变量值相同, 但是类型不一致

// 不可变更的常量 const strConst = 'this is string' // 可变变量 let str = 'this is string' 复制代码

使用let声明了一个可变变量, 使用const声明了一个不可变变量.
缺省类型注解的情况下, 不可变变量的类型为赋值字面量的类型, 可变变量的类型会转换为赋值字面量类型的父类型(比如const str的类型为'this is string', let num = 1, num的类型为number).
. 未缺省情况下, const声明变量的类型即声明的类型.

image.png

image.png

类类型

声明类的时候, 其实我们也同时声明了一个特殊的类型(确切的将是一个接口类型), 这个类型的名字就是类名, 表示类实例的类型; 在定义类的时候, 我们声明的除构造函数外所有属性, 方法的类型就是这个特殊类型的成员.

  1. 派生类如果包含一个构造函数, 则必须在构造函数中调用super方法, 这是Typescript强制执行的一条重要规则.

  2. 访问修饰符: public, private, protected

  3. 只读修饰符: readonly

  4. 存取器: getter, setter

class Dog {     private lastName: string = 'stack'     get myLastName() { return this.lastNmae }     set myLastName(name: string) {         if (name === 'xxx') {this.lastName = name}         else { console.error('xmxmxm') }     } } 复制代码

  1. 静态属性: 实例属性和方法,只有类在实例化时才会被初始化. 静态属性可以通过类名直接调用

class MyArray {     static dispalyName = 'myArray'     static isArray (obj: unknown) {         return Object.prototype.toString.call(obj).slice(8, -1) === 'Array'     } } console.log(MyArray.displayName) // myArray console.log(MyArray.isArray([])) // true 复制代码

基于静态属性的特性, 我们往往会把与类相关的常量, 不依赖实例this上下文的属性和方法定义为静态属性, 从而避免数据冗余, 进而提升运行性能.

抽象类

一种不能被实例化, 仅能被子类继承的特殊类.

我们可以使用抽象类定义派生类需要实现的属性和方法, 同时也可以定义其他被继承的默认属性和方法.

抽象类与接口区别

接口只能定义成员和类型, 抽象类可以定义成员,类型和方法实现

abstract class Adder {     abstract x: number;     abstract y: number; // 需要继承实现的     abstract add(): number;           displayName = 'Adder'; // 不需要继承实现          addTwice(): number {         return (this.x + this.y) * 2     } } class NumberAdder extends Adder {     x: number; // 基类使用abstract修饰, 子类必须重新声明     y: number;     add(): number {         return this.x + this.y     } } 复制代码

使用

  1. Number、String、Boolean、Symbol包装类型与基础类型不同,注意区分

  2. ts(2322)是一个静态类型检查的错误,在注解的类型和赋值的类型不同的时候就会抛出这个错误

  3. 数组类型的值只有显示添加了元组类型注解后(或者使用 as const,声明为只读元组),TypeScript 才会把它当作元组,否则推荐出来的类型就是普通的数组类型

  4. any 除非有重组的理由, 否则应尽量避免使用any, 并且开启禁用隐式any的设置

  5. unkown(3.0+) 在类型上更安全. 比如可以加将任意类型的值复制给unknown, 但anknown类型的值只能复制给unknown或any.  使用unknown后, typescript会对它做类型检测. 但是, 如果不缩小类型(type narrowing), 我们对unknown的任何操作都会出现错误

  6. void, undefined, null 用到的不多, 可以将undefined的值或类型时undefined的变量赋值给void类型, 反过是void但值是undefined的变量不能赋值给undefined类型.

let undeclared:undefined = undefined let unusable:void = undefined unusable = undeclared // ok undeclared = unusable // ts:2322 复制代码

概念

类型推断, 上下文推断

ts可以根据赋值类型或者上下文,推断出变量的类型

赋值推断

let x1 = 42; //number let x2: number = x1; //ok 复制代码

上下文推断

type Adder = (a:number, b:number) => number; const add:Adder = (a, b) => a + b // 推断出a,b为number类型 复制代码

字面量类型拓宽 Literal widening

可变变量的类型转换为父类型的设计我们称之为"literal widening", 也就是字面量类型拓宽.

const str = 'this is string'  // 类型为'this is string' const str1 = 'this is string' // 类型为string specifiedStr = str; // ts(2322) str = specifiedStr 复制代码

应用
// 字符串字面量类型 type Direction = 'up' | 'down' // 布尔字面量类型 type isEnable = true | false // 数字字面量类型 type margin: 0 | 2 | 4 复制代码

类型拓宽(Type Widening)

非严格模式下, TypeScript 对某些特定类型有类似字面量类型拓宽的设计. 比如对null和undefined的类型拓宽. 通过let, var声明的变量如果满足为显示声明类型注解且被赋予了null或者undefined值, 则推断出这些变量的类型为any.

let x = null; // 类型扩宽为any let y = undefined; // 类型拓宽为any type X = typeof x; // X 为any类型 复制代码

类型缩小 Type Narrowing

通过某些操作, 将变量的类型有一个较为宽泛的集合缩小到较小, 较明确的集合.

let func = (param: any) => {     if (typeof param === 'string') {      // 明确param为string类型, 因此可以调用String原型链上的方法         return param.toUpperCase()      } else if (typeof param === 'number') {         return param.toFixed(2)     }     return null } 复制代码

联合类型

使用|表示联合类型(string | undefined, 表示为string或undefined类型)

交叉类型

freshness

鼠标分别放在x1, x2, x3, x4 上方, x1, number, x2 string, x3 number, x4 number

interface P1 {     name: string } interface P2 extends P1 {     age: number } function convert(x: P1): number function convert(x: P2): string; function convert(x: P1 | P2): any {} const x1 = convert({name: ''}) // number const x2 = convert({name: '', age: 0}) // string const x3 = convert({name: ''} as P1) // number const x4 = convert({name: '', age: 0} as P2) // number 复制代码

关于x2和x4使用断言和不使用断言的解释:

  1. 函数重载是从上往下匹配, 针对x4, 因为P2继承P1, 所以类型为P2的参数和类型为P1的参数一样匹配到第一个重载, 进而推断出来的是number. 为了避免这种情况, 可以将covert的两个重载函数声明调换位置.

  2. TS 里对于对象字面量有一个 freshness 的概念,使用断言是为了避开它,如果不使用断言,匹配会对比对象的每一个属性,因此 x2 就匹配不到 P1,而会匹配上 P2。


作者:岩酱
链接:https://juejin.cn/post/7018872966481969182


文章分类
后端
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐