ts关键字操作符

2021/2/6 TS

🌙 keyof关键字

keyofObject.keys略有相似,只是 keyof 是取 interface 的键,而且 keyof 取到键后会保存为联合类型

interface IUserInfo {
    name: string;
    age: number;
}


function getValue<T extends Object, K extends keyof T>(o: T, key: K): T[K] {
    return o[key];
}

const obj1 = {name: 'xx', age: 18};
const a = getValue(obj1, 'name');

// name、age
type keys = keyof IUserInfo;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

🌙 in关键字

用于取联合类型的值。主要用于数组和对象的构造。

type name = 'firstName' | 'lastName';

type TName = {
    [key in name]: string;
}
1
2
3
4
5

🌙 infer关键字

推断类型:

  • 只能出现在有条件类型的 extends 子语句中;
  • 出现 infer 声明,会引入一个待推断的类型变量;
  • 推断的类型变量可以在有条件类型的 true 分支中被引用;
  • 允许出现多个同类型变量的 infer

🌙 获取函数参数 Parameters

type TArea = (width: number, height: number) => number;

type MyParameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any ? P : never;

type params = Parameters<TArea>;
1
2
3
4
5

🌙 获取函数ReturnType

type MyReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => infer R ? R : any;

type returnType = ReturnType<TArea>
1
2
3

🌙 获取实例类型 InstanceType

type MyInstanceType<T extends new (...args: any[]) => any> = T extends new (...args: any[]) => infer R ? R : any;
1

🌙 获取构造函数类型ConstructorParameters

type MyConstructorParameters<T extends new (...args: any[]) => any> = T extends new (...args: infer P) => any ? P : never;
1

🌙 获取参数 this 参数 ThisParameterType

type MyThisParameterType<T> = T extends (this: infer U, ...args: any[]) => any ? U : unknown;
1

以上均存在内置类型:

  • Parameters 获取函数参数类型

  • ReturnType 获取函数返回类型

  • InstanceType 获取实例类型

  • ConstructorParameters 获取构造函数参数类型

  • ThisParameterType 获取函数this类型

  • OmitThisParameter 剔除 this 参数

🌙 练习1

假设有一个这样的类型:

interface initInterface {
    count: number;
    message: string;

    asyncMethod(input: Promise<string>): Promise<Action<number>>;

    syncMethod(action: Action<string>): Action<number>;
}
1
2
3
4
5
6
7
8

在经过 Connect 函数之后,返回值类型为:

interface Result {
    asyncMethod(input: string): Action<number>;

    syncMethod(action: string): Action<number>;
}
1
2
3
4
5

其中 Action<T> 的定义为:

interface Action<T> {
    payload?: T
    type: string
}
1
2
3
4

现在要求写出Connect的函数类型定义。

答案:

type ans = Connect<initInterface>

//  非函数属性去除
type RemoveNonFunctionProps<T> = {
    [K in keyof T]: T[K] extends Function ? K : never;
}[keyof T]

//  将只包含函数属性的类型Pick出来
type PickFunction<T> = Pick<T, RemoveNonFunctionProps<T>>;

type TransformMethod<T> = T extends (
    input: Promise<infer U>
    ) => Promise<Action<infer S>>
    ? (input: U) => Action<S>
    : T extends (action: Action<infer U>) => Action<infer S>
        ? (action: U) => Action<S>
        : never;

type ConnectAll<T> = {
    [K in keyof T]: TransformMethod<T[K]>;
};

type Connect<T> = ConnectAll<PickFunction<T>>;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

🌙 练习2

有原数组如下:

const data1 = [
    {
        a1: 'a',
        b1: 'b',
        c1: 'c'
    }
];
1
2
3
4
5
6
7

请实现transformData

const A1 = transformData(data1, {a1: 'a2'}); // 返回 [{a2: 'a'}]
const A2 = transformData(data1, {a1: 'a2', b1: 'b2'}); // 返回 [{a2: 'a', b2: 'b']
1
2

做了两件事儿:

  • 1.替换key
  • 2.过滤掉没有被替换的key

答案:

interface Item {
    [K: string]: string
}

function transformData<T extends Object>(arr: T[], obj: Partial<T>) {
// 先替换key再过滤
    return arr.map(item => {
// 获取ikeys
        let itemKeys = Object.keys(item);
        let objKeys = Object.keys(obj);

        let newObj = {};
        // 替换key
        objKeys.forEach(ok => {
            itemKeys.forEach(ik => {
                if (ok === ik) {
                    newObj[obj[ok]] = item[ik]
                }
            })
        })
        return newObj;
    })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23