TypeScript

1.1TypeScript的介绍

        TS是JavaScript的超集(js有的TS都有)

        TypeScript = type + JavaScript(在js的基础上,为js添加类型支持)

ts相比js的优势

        1.更早的发现错误,减找少Bug,改Bug的时间,提升开发效率。

        2.程序任何位置都有代码提示,增加开发体验

        3.强大的类型系统提升的代码的可复用性,使得重构代码更加容易

        4.支持最新的ECMAscript语法

        5.TS的类型推断机制,不需要在代码的每一个地方都显示标注类型

1.2安装编译TS的工具包

        node.js只认识js代码不认识ts代码,所以童工tsc命令,实现ts -> js的转换。

        安装命令:npm i -g typescript

        验证安装是否成功:tsc -v(查看typescript的版本)

  •  编译运行ts代码
  1. 创建hello.ts文件,在终端输入 tsc hello.ts(会出现一个同名的js文件)
  2. 执行js文件,输入 node hello.js
  • 优化ts运行步骤(内部还是将ts转换为js,在运行js代码)
  1. 使用ts-node包,直接在node当中运行ts代码
  2. 安装命令: npm -g ts-node 
  3. 使用方法:ts-node hello.ts

1.3TypeScript常见的数据类型

        ts新增数据类型:联合类型,自定义类型,接口,元组,字面量类型,枚举,void,any等

1.3.1类型注解

1.数字类型

let age:number = 18

:number就是类型注解,约定变量必须是number

 2.数组类型的2种写法

let numbers:number[] = [1,2,3,4]
let strs:Array<string> = ['a','b']

如果数组当中既有数字也有字符串

let arr:(number | string)[] = [1,'a',2,'b']

| 叫联合类型 (当有多个类型组合的类型,表示可以是这些类型的任意一种)

1.3.2类型别名


let arr1: (number | string)[] = [1, 2, 3, 'one', 'two', 'three']
let arr2: (number | string)[] = [1, 2, 3, 'on', 'tw', 'three']

//上面2个类型重复了可以使用类型别名
// 类型别名 
type CustArray = (number | string)[]
let arr3: CustArray = [1, 2, 3, 13, 'af', 'afa']

1.3.3函数类型

指的是函数参数和函数返回值的类型

        1.单独指定参数,返回值的类型:

//1.单独指定参数,返回值类型

function add(number1:number,number2:number):number{

  return number1+number2

}

console.log(add(1,2));

//函数表达式

const add2 = (number1:number,number2:number):number =>{

return number1-number2

}

console.log(add2(3,1));

2.同时指定参数,返回值类型

const add3:(number1:number,number2:number) => number = (number1,number2) => {

  return number1+number2

}

3.函数没有返回值的时候 添加void


//函数没有返回值的时候 添加void
function greet(name: string): void {
  console.log('hello', name)
}
greet('cui')

1.3.4函数的可选参数

不加问号就表示必须传递2个参数

// 必选参数必须在可选参数之前 在函数参数之后添加?
function mySlice(start?: number, end?: number): void {
  console.log('开始', start, '结束', end)

}
mySlice()
mySlice(1)
mySlice(1, 2)

1.3.5对象类型

 let person:{name:string;age:number;sayHi():void,greet(name:string):void} = {  
   name:'崔',
   age:18,
   sayHi() {
   },
   greet(name){}
 }
// 多行可以省略;
let person: {
  name: string
  age: number
  sayHi:()=>void
  greet(name: string): void
} = {
  name: '崔',
  age: 18,
  sayHi() {

  },
  greet(name) { }
}

1.3.6对象的可选属性

function myAxios(config: { url: string; method?: string }) { }
myAxios({
  url: ''
})

1.3.7接口

当一个对象的类型被多次使用时,一般会使用接口(interface)来描述对象的类型,达到复用的目的

步骤:

  1. 使用interface关键字来声明接口
  2. 接口名称是合法的变量名称
  3. 声明接口后直接使用接口名称作为变量的类型
  4. 因为每一行只有一个属性类型,因此属性后面没有;
接口  interface
 interface IPerson {
   name: string
   age: number
   sayHai(): void
 }
 类型别名
type IPerson = {
  name: string
  age: number
  sayHai(): void
}


let person: IPerson = {
  name: '崔',
  age: 18,
  sayHai() {
  }
}

interface(接口) 和 type(类型别名)的区别对比

        1.相同点:都可以为对象指定类型

        2.不同点:

  • 接口只可以为对象指定类型
  • 类型别名,不仅可以为对象指定别名,实际还可以为任意类型指定别名

1.3.8接口继承

通过extends继承后会获取所有的属性跟方法

//接口继承 extends
interface Ponint2D { x: number; y: number }
// interface Ponint3D {x:number;y:number;z:number}

// 使用继承实现复用
interface Ponint3D extends Ponint2D { z: number }

let p3: Ponint3D = {
  x: 1,
  y: 2,
  z: 3
}

1.3.9元组

// let position:number[] = [1,354,56,465,46,54,5]

// 使用元组 记录位置信息 中括号里面标记有多少个元素以及每个元素的类型
let position: [number, number] = [39, 55] // 必须是2个数字的数组

1.3.10类型推论

//1. 声明 变量并立即赋值的时候可以省略类型
let age = 18

// 如果声明变量没有立刻赋值,此时必须要手动添加类型注解
let a: number
a = 15

// 2.决定函数返回值的时候,可以省略函数返回值的类型(必须指定参数的类型)
function add(number1:number,number2:number){
  return number1+number2
}

1.3.11类型断言

当你比ts更加明确一个值的类型,此时可以用类型断言来指定具体类型

比如 const alink = document.getElementById('link')   此时只能获取HTMLElement的公共属性,不能获取自己独有的属性比如a标签的href属性,所以as后面加上类型断言

// 写法1 const alink = <HTMLAnchorElement>document.getElementById('link')
// 写法2   
const alink = document.getElementById('link') as HTMLAnchorElement;
alink.id

console.dir($0)来获取标签的类型 例如a标签(HTMLAnchorElement)

1.3.12字面量类型

str1的类型为string

str2的类型为'hello ts'  这个就是一个字面量类型

str3也是一个字面量类型 'cui'

字面量的值只能是字面量自己,字面量类型一般配合联合类型 | 使用

let str1 = 'hello ts'

const str2:'hello ts' = 'hello ts'

const str3 = 'cui'

let age:18 = 18
// 使用场景 贪吃蛇上下左右
function changeDir(direction:'up'|'down'|'left'|'right'){

}
changeDir('down')

1.3.13枚举类型(会被编译为js代码,其他类型不会,会被移除)

枚举:定义一组命名常量,它描述一个值,该值可以是这些命名常量当中的一个(会被编译成js代码)

enum

通过 . 语法来访问枚举当中的成员

数字枚举具有自增的情况

// 枚举
enum Directio{
  up,
  down,
  left=18, // 数字枚举
  right
}

function changeDire (direction:Directio) {
console.log(direction); 

}
changeDire(Directio.left)//19   只能是枚举成员当中的一个

字符串枚举

所有枚举成员的值都必须初始化为字符串

注意:字符串枚举没有自增行为,所以枚举成员必须赋值

// 枚举
enum Directio{
  up ="up",
  down ="down",
  left ="left",
  right ="right"
}

function changeDire (direction:Directio) {

}

changeDire(Directio.left)//19   只能是枚举成员当中的一个

console.log(Directio); //{ up: 'up', down: 'down', left: 'left', right: 'right' }

1.3.14 any类型

原则:不推荐使用any这会让ts类型失去保护的优势,因为当值的类型为any时,可以对值镜像任何操作,并且不会有代码提示

其他隐试具有any类型的情况:1.声明变量时既不给类型也不付初始值          2.函数参数不加类型

// 不推荐使用any 这会让ts失去类型保护的优势

//隐试具有any类型的情况 1.声明变量不提供类型也不提供值 2.函数参数不加类型
let a

function add(num1, num2) { }




let obj: any = { x: 0 };
obj.abc = true
obj()
//赋值给其他类型的变量
const n : number = obj

1.3.15 typeof 

使用typeof来获取变量p的类型,结果与对象字面量形式的类型相同,typeof出现在类型注解的位置,所处的环境就是类型的上下文,注意:typeof 只能查询变量或属性的类型,不能查询其他形式的类型(如函数调用的类型)

console.log(typeof 'hello world'); //string

let p = {x: 0, y: 1}

function test(point:typeof p) { }
// function test(point:{x:number;y:number}) { }

test(p)

let num: typeof p.x

function add(num1:number,num2:number) { 
return num1 + num2
}

// let ret : typeof add(1,2) //typeof 只能查询变量或属性的值,不能查询其他形式的类型(如函数调用的类型)

1.4ts的高级类型

1.4.1class类

ts引入的class关键字,并为其添加类型注解和其他语法(比如可见修饰符等)

ts当中的class,不仅提供了class的语法功能,也作为一种类型存在

        实例属性初识化:

class Person { 
  age: number
  // gender:string ='男'
  gender ='男'

}

const p = new Person()
p.age
p.gender

        构造函数:

class Person { 
  age: number
  gender: string
  constructor(age: number, gender: string) { 
    this.age = age
    this.gender = gender

  }
}
//constructor() 方法是一种特殊的方法(构造方法),用于创建和初始化在类中创建的对象。

// 创建对象时会自动调用构造方法 constructor()。

// 如果没有显式指定构造方法,则会添加默认的 constructor 方法。

// 如果不指定一个构造函数 (constructor) 方法,则使用一个默认的构造函数 (constructor)。

// 在一个构造方法中可以使用 super 关键字来调用一个父类的构造方法。

const p = new Person(18, '男')
console.log(p.age,p.gender);//18 男

注意:成员初识化后才可以使用this.age来访问实例成员,需要为构造函数指定类型注解,否者会隐试推断为any,构造函数不需要返回值类型
 

实例方法:方法的类型注解与函数相同

class Point { 
  x = 0; y = 1;
  

  scale(n: number):void{ 
    this.x *= n;
    this.y *= n;
  }
}
const q = new Point()

q.scale(2)
console.log(q.x, q.y) //0 2

类的继承:

1.extends(继承父类) 2.implements (实现接口)

js只有extends ,implements是ts提供的

        extends(继承父类)

class Animal { 
  age = 18
  move() { console.log('不要狗叫');
  }
}

// extends 继承父类所有的属性跟方法

class Dog extends Animal {
  name = '二哈'
  bark() { console.log('汪汪') }
}

const dog = new Dog()
dog.move()

dog.bark()
console.log(dog.age);

console.log(dog.name);

        implements (实现接口)

interface Sing { 
  sing(): void
  age:number
}
//implements 让class实现接口   Song 实现Sing接口   意味着Song提供Sing提供的属性跟方法
class Song implements Sing {
  age = 18
  sing() {
    console.log('唱歌')
  }
}

成员可见性(public)[ˈpʌblɪk]

//父类

//public 表示公开的 公共成员可以被任何成员访问,默认就是public
class Animal { 
 public move() { 
    console.log('跑步');
  }
}

//子类
class Dog extends Animal { 
  bark() { 
    console.log("汪汪");
    
  }
}

const d = new Dog()

d.move()

受保护的protected([prəˈtektɪd])

//protected 受保护的  仅在声明的类跟子类当中可见   (实例对象是不可见的)
// 子类可以通过this来访问父类中被保护的成员

class Animal { 
  protected move() { 
    console.log('gogo');
    
  }
}

class Dog extends Animal { 
  back() { 
    console.log('王');
    this.move();
  }
}

const r = new Animal()
// r.move()  属性“move”受保护,只能在类“Animal”及其子类中访问。
const a = new Dog()
// a.move()   性“move”受保护,只能在类“Animal”及其子类中访问。

私有的privere

// private 只在当前的类当中可以使用 , 自己的实例对象,子类的类跟实例对象都不能访问

class Animal { 
  //私有的
  private arun() { 
  console.log("跑步");
  }
  
}

const a = new Animal();
// a.arun();  属性“arun”为私有属性,只能在类“Animal”中访问

class Dog extends Animal { 
  //公有的
  public bark() { 
  console.log("����");
  }
  // this.arun()  
}

const dog = new Dog();

// dog.arun();  属性“arun”为私有属性,只能在类“Animal”中访问

 readonly(只读修饰符)防止构造函数之外的对属性进行赋值

class person { 
  //只读属性 readonly
  readonly name: string = "John";  // 如果不加:number 那么name 就会变成一个字面量类型

  constructor(name: string) {
  this.name = name;
  }

  //readonly 不能修饰方法只能修饰属性

}

//接口   readonly
interface Person1 {
  readonly age:number
}

let obj: Person1 = {
  age:18
} 
obj.age = 19  // 错误 因为age是只读属性


// 对象 readonly


let obj2: {age:number} = {
  age:18
} 
obj.age = 19  // 错误 因为age是只读属性

1.4.2类型兼容性

两种类型系统:1 Structural Type System(结构化类型系统) 2 Nominal Type System(标明类型系统)。
TS 采用的是结构化类型系统,也叫做 duck typing(鸭子类型),类型检查关注的是值所具有的形状。
也就是说,在结构类型系统中,如果两个对象具有相同的形状,则认为它们属于同一类型。

class Point { x: number; y: number }
class Point2 { x: number; y: number }

const p:Point = new Point2()

解释:
1. Point 和 Point2D 是两个名称不同的类。
2. 变量 p 的类型被显示标注为 Point 类型,但是,它的值却是 Point2D 的实例,并且没有类型错误。
3. 因为 TS 是结构化类型系统,只检查 Point 和 Point2D 的结构是否相同(相同,都具有 x 和 y 两个属性,属性类型也相同)。
4. 但是,如果在 Nominal Type System 中(比如,C#、Java 等),它们是不同的类,类型无法兼容。

注意:在结构化类型系统中,如果两个对象具有相同的形状,则认为它们属于同一类型,这种说法并不准确。
更准确的说法:对于对象类型来说,y 的成员至少与 x 相同,则 x 兼容 y(成员多的可以赋值给少的)。

class Point4 { x: number; y: number }
class Point3 { x: number; y: number; z: number}

const p1: Point4 = new Point3()

解释:
1. Point3的成员至少与 Point4 相同,则 Point4 兼容 Point3。
2. 所以,成员多的 Point3 可以赋值给成员少的 Point4。

除了 class 之外,TS 中的其他类型也存在相互兼容的情况,包括:1 接口兼容性 2 函数兼容性 等。

1 接口兼容性
        接口之间的兼容性,类似于 class。并且,class 和 interface 之间也可以兼容。

// 接口的兼容性

interface Point5 { x: number; y: number }
interface Point6 { x: number; y: number }
interface Point7 { x: number; y: number; z: number }

class Point8 { x: number; y: number; z: number }


let p4: Point5


const p2: Point5 = new Point8()
let p3: Point6 = new Point8()

2 函数兼容性

1. 参数个数,参数多的兼容参数少的(或者说,参数少的可以赋值给多的)

解释:
1. 参数少的可以赋值给参数多的,所以,f1 可以赋值给 f2。
2. 数组 forEach 方法的第一个参数是回调函数,该示例中类型为:(value: string, index: number, array: string[]) => void。
3. 在 JS 中省略用不到的函数参数实际上是很常见的,这样的使用方式,促成了 TS 中函数类型之间的兼容性。
4. 并且因为回调函数是有类型的,所以,TS 会自动推导出参数 item、index、array 的类型。

2. 参数类型,相同位置的参数类型要相同(原始类型)或兼容(对象类型)。

解释:
1. 注意,此处与前面讲到的接口兼容性冲突。
2. 技巧:将对象拆开,把每个属性看做一个个参数,则,参数少的(f2)可以赋值给参数多的(f3)。

3. 返回值类型,只关注返回值类型本身即可:

解释:
1. 如果返回值类型是原始类型,此时两个类型要相同,比如,左侧类型 F5 和 F6。
2. 如果返回值类型是对象类型,此时成员多的可以赋值给成员少的,比如,右侧类型 F7 和 F8。

//函数兼容性(参数少的可以赋值给参数多的)

type F1 = (a: number) => void;
type F2 = (a: number,b:number) => void;
let f1:F1
let f2:F2
f2 = f1

1.4.3交叉类型

//交叉类型(&) :功能类似于接口继承(extends),用于组合多个类型为一个类型(常用于对象类型)

交叉类型与组合类型的对比

相同到哪: 都可以实现对象类型的组合

不同点 :两种方式实现类型组合时,对于同名属性之间,处理类型冲突的方式不同

 接口继承会报错 交叉类型没有错误,可以简单理解为  fn:(value : string | number) => string

interface Person { name: string }
interface User { phone: string }

type PersonData = Person & User

let obj: PersonData = {
  name: 'cui',
  phone: '18888888888'
}

1.4.4泛型

        泛型的应用场景:泛型在保护类型的同时,可以让函数等于多种不同类型一起工作,灵活可复用

// 泛型可以在保证类型安全的情况下,让函数与多种类型一起工作 ,从而实现复用,常用于:函数,接口,class 中
// 需求:创建一个id函数,传入什么数据就返回数据本省(也就是参数和返回值的类型相同)

function id(value: number): number { 
  return value
}
//这时候函数只能接受number类型的数据,

//为了让函数具备接收任何类型,可以将参数改成any,但是 这样就失去TS的类型保护,类型不安全
function add(value: any): any { 
  return value
}

//泛型在保护类型的同时,可以让函数等于多种不同类型一起工作,灵活可复用

1.泛型函数

        

//1.语法:在函数名称后面添加<>(尖括号),尖括号类指定具体的类型

// 2.当传入类型number后,这个类型会被声明的变量type捕获到

// 3.此时Type 的类型就是number ,所以函数id参数和返回值的类型都时number

//1.语法:在函数名称后面添加<>(尖括号),尖括号类指定具体的类型
// 2.当传入类型number后,这个类型会被声明的变量type捕获到
// 3.此时Type 的类型就是number ,所以函数id参数和返回值的类型都时number

function id<type>(value: type): type { 
  return value;
}

const num = id<number>(10)
const str = id<string>('string')

//函数调用是可以省略<>
const num = id(110)

 这样通过泛型函数就就做到了让id函数与多种不同的类型一起工作,实现复用的同时保证的类型的安全

2.泛型约束

泛型约束:默认情况下,泛型函数的类型变量Type可以代表多个类型,这导致无法访问任何属性

 比如 , id("q") 调用函数时就无法获取参数的长度


function id<type>(value: type) { 
  console.log(value.length);// 类型Type上不存在属性length
  return value;
} 

原因:因为Type表示任何属性,无法保证一定存在length属性,不如number就没有length属性

此时需要为泛型添加约束来收缩类型(缩窄类型的取值范围)

2.1 指定更加具体的类型Type[] (Type类型的数组),因为只要是数组就一个存在length属性,因此就可以访问了。

function id<Type>(value: Type[]) { 
  return value.length
}

2.2添加约束

1.创建描述约束的接口length,该接口要求提供length属性

2.通过extends关键字使用接口,为泛型添加约束

3.该约束表示:传入的类型必须具有length属性。

// 注意: 传入的实参只要有length属性即可,这也符合前面讲到的接口的类型兼容性。

interface ILength { length: number; }
function id1<Type extends ILength>(value: Type): Type { 
  return value
}
id1(['abc'])
id1("abc")
id1(123)//类型“number”的参数不能赋给类型“ILength”的参数

2.3类型变量之间的约束

// 解释:

 /*  1.添加了第二个类型的变量,2个类型变量之间用(,)分隔

      2.keyof关键字接收一个对象类型,生成一个键名称的联合类型。

      3.keyof Type 实际上是获取的cui对象的所有键的联名类型,也就是 'name' | 'age'

      4.类型变量Key收Type的约束只能是Type所有键当中的任意一个

 */

function getProp<Type, key extends keyof Type>(obj: Type, key: key) { 
  return obj[key]
}
let cui = {
  name: 'cui',
  age:18
}
getProp(cui, 'name',)

2.4泛型接口

泛型接口:接口也可以配合泛型来使用,以增加其灵活性,增加复用性

interface IdFunc<type> { 
  id: (value: type) => type
  ids:()=> type[]
}

let obj: IdFunc<number> = {
  id(value) { return value },
  ids() { return [1,2,3] }
}

解释:

1. 在接口名称的后面添加 <类型变量>,那么,这个接口就变成了泛型接口。

2. 接口的类型变量,对接口中所有其他成员可见,也就是接口中所有成员都可以使用类型变量。

3. 使用泛型接口时,需要显式指定具体的类型(比如,此处的 IdFunc<nunber>)。

4. 此时,id 方法的参数和返回值类型都是 number;ids 方法的返回值类型是 number[]。

 实际上js的数组在ts当中就是一个泛型接口

2.5泛型类

class Genng<Type> { 
  default: Type
  add: (x: Type, y: Type) => Type
}

const newadd = new Genng<number>()

newadd.default = 12

2.6泛型工具类

        1.Partial<Type> [ˈpɑːʃl]

//泛型工具类型 - Partial<Type> 用来构造(创建)一个类型,将 Type 的所有属性设置为可选。

//解释:构造出来的新类型 PartialProps 结构和 Props 相同,但所有属性都变为可选的。

interface Prage { 
  name: string,
  age:18
}

type prage = Partial<Prage>
/* type prage = {
    name?: string | undefined;
    age?: 18 | undefined;
}

*/

        2.Readonly<Type>  [ˌriɑˈdɔnli]

泛型工具类型 - Readonly<Type> 用来构造一个类型,将 Type 的所有属性都设置为 readonly(只读)

interface Person1 {
  id: string
  titles: string
  children: number[]
}

type obj = Readonly<Person1>
/*

type obj = {
    readonly id: string;
    readonly titles: string;
    readonly children: number[];
}

*/

const a: obj = {
  id: '123',
  titles: '123',
  children: [1,2,3]
}
a.children = [1,2,3] //无法为“children”赋值,因为它是只读属性

        3.Record<Keys,Type>  [ˈrekɔːd , rɪˈkɔːd]

泛型工具类型 - Record<Keys,Type> 构造一个对象类型,属性键为 Keys,属性类型为 Type。

// 泛型工具类型 - Record<Keys,Type> 构造一个对象类型,属性键为 Keys,属性类型为 Type。

type RecordObj = Record<'a' | 'b' | 'c', string[]>
let Obj: RecordObj = {
  a: ['1', '2', '3'],
  b: ['1', '2', '3'],
  c: ['1', '2', '3']
}

解释:
1. Record 工具类型有两个类型变量:1 表示对象有哪些属性 2 表示对象属性的类型。
2. 构建的新对象类型 RecordObj 表示:这个对象有三个属性分别为a/b/c,属性值的类型都是 string[]。

1.4.5索引签名类型

        绝大多数情况下,我们都可以在使用对象前就确定对象的结构,并为对象添加准确的类型。
使用场景:当无法确定对象中有哪些属性(或者说对象中可以出现任意多个属性),此时,就用到索引签名类型了。

interface AnyObject { 
  [key: string]:number
}

let OBJ: AnyObject = {
  a: 1,
  b: 2,
  c: 3
}

解释:
1. 使用 [key: string] 来约束该接口中允许出现的属性名称。表示只要是 string 类型的属性名称,都可以出现在对象中。
2. 这样,对象 obj 中就可以出现任意多个属性(比如,a、b 等)。
3. key 只是一个占位符,可以换成任意合法的变量名称。
4. 隐藏的前置知识:JS 中对象({})的键是 string 类型的。

在 JS 中数组是一类特殊的对象,特殊在数组的键(索引)是数值类型。
并且,数组也可以出现任意多个元素。所以,在数组对应的泛型接口中,也用到了索引签名类型。


解释:
1. MyArray 接口模拟原生的数组接口,并使用 [n: number] 来作为索引签名类型。
2. 该索引签名类型表示:只要是 number 类型的键(索引)都可以出现在数组中,或者说数组中可以有任意多个元素。
3. 同时也符合数组索引是 number 类型这一前提。

interface MyArray<T> { 
  [index: number]: T
}

let arr: MyArray<number> = [1, 2, 3]

1.4.6映射类型

映射类型:基于旧类型创建新类型(对象类型),减少重复、提升开发效率。

type PropKey = 'a' | 'b' | 'c' | 'd' 
type Type1 = { a: number, b: number, c: number }

type Type2 = { [key in PropKey]: number }

解释:
1. 映射类型是基于索引签名类型的,所以,该语法类似于索引签名类型,也使用了 []。
2. Key in PropKeys 表示 Key 可以是 PropKeys 联合类型中的任意一个,类似于 forin(let k in obj)。
3. 使用映射类型创建的新对象类型 Type2 和类型 Type1 结构完全相同。
4. 注意:映射类型只能在类型别名中使用,不能在接口中使用。

映射类型除了根据联合类型创建新类型外,还可以根据对象类型来创建:

type Props = { a: number, b: number, c: number, d: number }
type Props3 = { [key in keyof Props]: number }


解释:
1. 首先,先执行 keyof Props 获取到对象类型 Props 中所有键的联合类型即,'a' | 'b' | 'c'。
2. 然后,Key in ... 就表示 Key 可以是 Props 中所有的键名称中的任意一个。

 T[P] 语法,在 TS 中叫做索引查询(访问)类型。
作用:用来查询属性的类型。

解释:Props['a'] 表示查询类型 Props 中属性 'a' 对应的类型 number。所以,TypeA 的类型为 number。

注意:[] 中的属性必须存在于被查询类型中,否则就会报错。

索引查询类型的其他使用方式:同时查询多个索引的类型

解释:使用字符串字面量的联合类型,获取属性 a 和 b 对应的类型,结果为: string | number。

 

解释:使用 keyof 操作符获取 Props 中所有键对应的类型,结果为: string | number | boolean。

  • 18
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值