Typescript:基于另一个属性值强制属性类型,该属性值是泛型的关键

use*_*188 2 types typescript typescript-generics

给定以下类型:

export type MyType = {
    a: boolean;
    b: number;
}
Run Code Online (Sandbox Code Playgroud)

我想创建一个类型:

export type Mapper<T> = {
    key: keyof T;
    func: (value: string) => T[key];
}
Run Code Online (Sandbox Code Playgroud)

这样我就可以拥有:

const mapToMyTypePropertyA: Mapper<MyType> = {
    key: "a",
    func: v => !!v // enforce output type to be the type of MyType["a"], which is boolean
};

const mapToMyTypePropertyA: Mapper<MyType> = {
    key: "b",
    func: v => v.length // enforce output type to be the type of MyType["b"], which is number
};
Run Code Online (Sandbox Code Playgroud)

即我想强制(这是一个函数)的返回类型是由(这是泛型类型的键)确定的泛型类型func的属性的类型。key

这可能吗?

到目前为止我只能做到这一点:

export type Mapper<T, K extends keyof T> = {
    key: K;
    func: (value: string) => T[K];
}
const mapToMyTypePropertyA: Mapper<MyType, "a"> = {
    key: "a",
    func: v => !!v // I get the enforcement here
}
Run Code Online (Sandbox Code Playgroud)

但这需要在泛型类型和属性中重复键两次key

moc*_*cha 9

您可以使用另一种类型来“生成”可能的对象:

type GenerateCombos<T> = {
    [K in keyof T]: {
        key: K;
        func: (value: string) => T[K];
    };
}[keyof T];
Run Code Online (Sandbox Code Playgroud)

这将为我们提供允许对象的并集。例如,GenerateCombos<{ foo: string }>只会给我们:

{ key: "foo"; func: (value: string) => string }
Run Code Online (Sandbox Code Playgroud)

GenerateCombos<MyType>给我们很好的类型:

{
    key: "a";
    func: (value: string) => boolean;
} | {
    key: "b";
    func: (value: string) => number;
}
Run Code Online (Sandbox Code Playgroud)

要使用它,您可以先给它一个别名:

type Mapper = GenerateCombos<MyType>;
Run Code Online (Sandbox Code Playgroud)

然后注释变量的类型:

const mapToMyTypeProperty1: Mapper = {
    key: "a",
    func: v => !!v // enforce output type to be the type of MyType["a"], which is boolean
};

const mapToMyTypeProperty2: Mapper = {
    key: "b",
    func: v => v.length // enforce output type to be the type of MyType["b"], which is number
};
Run Code Online (Sandbox Code Playgroud)

如果你做得不正确,它也会出错:

const mapToMyTypeProperty3: Mapper = {
    key: "a",
    func: v => v // ! error
};

const mapToMyTypeProperty4: Mapper = {
    key: "b",
    func: v => !!v // ! error
};
Run Code Online (Sandbox Code Playgroud)

在这里试试这个。