美文网首页
bunny笔记|TS基础(2):泛型函数、泛型约束、在泛型约束中

bunny笔记|TS基础(2):泛型函数、泛型约束、在泛型约束中

作者: 一只小小小bunny | 来源:发表于2022-04-29 14:49 被阅读0次

01

typescript的操纵类型

//从类型中创建类型:泛型类型、keyof类型操作符、typeof操作类型符、索引访问类型、条件类型、映射类型、模板字面量类型
//我们通过模板字面量的字符串来改变属性的映射类型


//软件工程的一个主要部分是建立组件,这些组件不仅有定义明确和一致的api,而且还可以重复使用,能够处理今天的数据和明天的数据,这些组件将为我们建立大型软件系统提供最灵活的能力,比如像c#和java这样的语言中,创建可重用组件的工具箱中有一个非常重要的工具,就是泛型。也就是说能够创建一个在各种类型上工作的组件,而不是单一的类型,这就使得用户可以消费这些组件,并且使用自己的类型。
/**例如:
function identity<type>(arg:Type):Type{
    return arg;
}
*/
//在函数名后添加一个Type的类型,这个Type允许我们捕获用户提供的类型,比如number,string,这样我们就可以在以后使用这些信息了,这里我们再次使用Type作为返回值,经过检查,我们看到参数的类型和返回的类型使用的是相同的type这个类型,这就使得我们可以讲类型信息从函数的一侧输入,然后从另一侧输出。我们说这个版本的函数是通用的,因为他在一系列的类型上面工作和我们使用any类型不同的是,它和我们第一次使用的number这个参数和返回number类型的identity,它的作用是一样的精确,也就是说它不会丢失任何的类型信息。写好通用函数,我们就可以使用两种方式来调用它了.
//第1种方式:我们将所有的参数包括类型参数都传递给函数,如
/**
  function identity<Type>(arg:Type):Type{
    return arg
}
let output=identity<string>("myString")//方式1
let output=identity("myString")//方式2
 */

//我们看在identify调动的时候加上一个<>定义泛型类型,这里写了<string>然后在()里传入实参

//第2种方式:使用类型参数推断,也就是说我们希望编译器根据我们传入的参数的类型,自动为我们设置这开发的值的类型,我们把string去掉

//使用通用类型
function loggingIdentify<Type>(arg: Type): Type {
    //console.log(arg.length);//报错,泛型类型Type上不存在length。但实际上是可以获取length的,但ts语法上不允许这样表达
    return arg;
}

//如果用户传入数组可以求值length,但是如果用户传入number那就获取不到length了,那就会产生问题,要传入数组,应如下改造:

function loggingIdentify2<Type>(arg: Array<Type>): Type[] {
    console.log(arg.length);
    return arg;
}
loggingIdentify2([1,2,3,4])

02

function identify<Type>(arg:Type):Type{
    return arg
}

//定义泛型函数的形式:()=>
//let myIdentity:()=>identify
//let myIdentity:(arg:Type)=>identify
let myIdentity:<Type>(arg:Type)=>Type=identify

//写成对象字面量的形式:{}=
//let myIdentity2:{key值}=identify
let myIdentity2:{<Type>(arg:Type):Type}=identify

//将泛型字面量的形式写成泛型接口
interface GenericIdFn{
    // ():Type
    <Type>(arg:Type):Type
}

let myIdentity3:GenericIdFn=identify

//接口方式的另一个写法,更灵活一些
interface GenericIdFn2<Type>{
    (arg:Type):Type
}

let myIdentity4:GenericIdFn2<string>=identify

03

class GenericNumber<NumType>{
    zeroValue: NumType
    add: (a: NumType, y: NumType) => NumType
}

let myGeneric = new GenericNumber<number>()
myGeneric.zeroValue = 0
myGeneric.add = function (x, y) {
    return x + y
}

let myGeneric2 = new GenericNumber<string>()
myGeneric2.zeroValue = ''
myGeneric2.add = function (x, y) {
    return x + y
}

04

泛型约束

interface Lengthwise{
    length:number
}

function loggingId<Type extends Lengthwise>(arg: Type): Type{
    console.log(arg.length);
    return arg;
}

loggingId(['hello',2,22])

05

在泛型约束中使用类型参数

function getProperty<Type, Key extends keyof Type>(obj: Type, key: Key) {
    return obj[key]
}

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

getProperty(x, 'a')


06

在泛型中使用类类型


// function creat<Type>(c: { new(): Type }): Type {
//     return new c();
// }

class Beekeeper {
    hasMask: boolean = true
}

class Zoo {
    nametag: string = 'Miki'
}

class Animal {
    numLegs: number
}

class Bee extends Animal {
    //定义一个属性,实例类
    keeper: Beekeeper = new Beekeeper()
}

class Lion extends Animal {
    keeper: Zoo = new Zoo()
}

//形参传入一个类,并返回类
function creatInstance<A extends Animal>(c:new()=>A): A {
    return new c();
}

creatInstance(Lion).keeper.nametag
creatInstance(Bee).keeper.hasMask
//creatInstance(Beekeeper)//报错,Beekeeper没有继承Animal

07

keyof类型操作符

type Point = { x: number; y: number };
type P = keyof Point;

const p1: P = 'x'
const p2: P = 'y'

//所以type P = keyof Point;的P的类型是 "x"|"y"联合类型

//索引签名

type Arrayish={
    [n:number]:unknown
}

type Mapish={
    [k:string]:boolean
}

type M=keyof Mapish

const m1:M='sss'
const m2:M=177
// const m3:M=false//报错,不能将类型boolean分配给类型"string|number"

08

typeof

//了解原生的type,console.log(typeof 'helloWorld');

// let s = "hello"
// let n: typeof s
// n = 'helll'
// n = 777 //报错,number不能分派给string类型

//预定义类型
//ReturnType<T>

// type Predicate = (x: unknown) => boolean
// type K = ReturnType<Predicate>

// function f() {
//     return {
//         x: 99,
//         y: 22
//     }
// }

// type PP=ReturnType<typeof f>
// const hh:PP={x:3,y:99}
// const p:PP=100//报错:不能将number分配给类型“{x:number,y:number}”

function msg() { }
let shouldC: typeof msg
//shouldC = 100 //报错:不能将类型number分配给类型()=>void

//注意:我们绝对不能在typeof的后边去调用这个函数试图去返回函数的返回结果的类型,这是由问题的。也就是说tyof只能是去修饰一个变量或者某个对象里的属性,不能修饰函数体类型

09

type Person = {
    age: number,
    name: string,
    alive: boolean
}

//通过索引的方式访问Person里面age属性
type Age = Person['age']
let age: Age = 99
//只能访问number类型

type Person2 = {
    age: number,
    name: string,
    alive: boolean
}

type L1 = Person2['age' | 'name']
let L11: L1 = 88
//可以访问number和string两种类型

type L2 = Person2[keyof Person2]
//age、name、alive三种类型都可访问


const MyArray = [
    { name: 'bunny', age: 18 },
    { name: 'heihei', age: 99 }
]

type Person3 = typeof MyArray[number]
let aaa:Person3={
    name:'bbb',
    age:44
}


//只能在类型使用索引

10

interface Animal {
    live(): void
}

interface Dog extends Animal {
    woof(): void
}

//type Example1=number
type Example1 = Dog extends Animal ? number : string

//type Example2=string
type Example2 = Dog extends Animal ? number : string

//泛型条件类型

interface IdLabel {
    id: number
}

interface NameLabel {
    name: string
}

type NameOrId<T extends number | string> = T extends number ? IdLabel : NameLabel

function createLable<T extends number | string>(idOrName: T): NameOrId<T> {
    throw ''
}

//type a=NameLable
let a = createLable('typescript')
//tyoe b=IdLabel
let b = createLable(25)

//type c =NameLable | IdLabel
let c = createLable(Math.random() > 0.9 ? 'hello bunny' : 250)

11

//条件类型约束

//type MessageOf<T>=T['message']
 type MessageOf<T extends {message:unknown}>=T['message']
 
 interface Email{
     message:string
 }

 type EmailMessageContents =MessageOf<Email>

 //如果我们想要MessageOf来接收任何类型,并且在Message这个属性不可用的情况下,把它默认为返回一个never类型,这时候就需要一个约束条件移出再引入另外一个条件类型了

 type MessageOf2<T>=T extends {message:unknown}?T['message']:never
 
 interface Email2{
    message:string
}

interface Dog{
    bark():void
}
type EmailMessageContents2 =MessageOf2<Email2>
const emc:EmailMessageContents2='hvdsjcvcf'

type DogMessageContents = MessageOf2<Dog>
// const dmc:DogMessageContents ='erro' //报错,不能将string分配给类型never ,可以加断言

const dmc:DogMessageContents ='erro' as never

12

在条件类型内进行推断

 type GetReturnType<Type>=Type extends (...arg:never[])=>infer Return?Return:number

 //type Nmu =number
 type Num =GetReturnType<()=>number>
 let num:Num =100

//type Nmu =string
 type Str = GetReturnType<(x:string)=>string>
 let str:Str=''

 //type Bools=boolean[]
 type Bools=GetReturnType<(a:boolean,b:boolean)=>boolean[]>
 let bools:Bools=[false,true]

 //type Never=never
 type Never = GetReturnType<string>
 let never:Never ='error' as never

function sn(x:string):number
function sn(x:number):string
function sn(s:string|number):string|number
function sn(s:string|number):string|number{
    return Math.random()>0.5 ? 'hello':23
}

//type T1=Return
type T1=ReturnType<typeof sn>
//const t1:T1=true//报错,不能将boolean分配给string|number

13

分布式条件类型


type ToArray<T> = T extends any ? T[] : never

type SN = ToArray<string | number>

//type SN = string[]|number[]
//type SN = (string|number)[]
//type SN =ToArray<string|number>
let saon: SN = []

//非分发式的ToArray

type TADist<T> = [T] extends [any] ? T[] : never
type SAON = TADist<string|number>

let san1:SAON =['1',22]
//let san:SAON =[true]//报错,不能将类型boolean分配给string|number

tsconfig.json

{
  "compilerOptions": {
    "target": "es2016",
    "module": "commonjs",
    "rootDir": "./src",
    "outDir": "./dist",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "strictPropertyInitialization": false,
    "skipLibCheck": true
  }
}

相关文章

网友评论

      本文标题:bunny笔记|TS基础(2):泛型函数、泛型约束、在泛型约束中

      本文链接:https://www.haomeiwen.com/subject/txesyrtx.html