用类型的选择键来定义类型以创建对象似乎被破坏了

时间:2019-04-20 23:11:29

标签: typescript

为什么不起作用?

class Demo<T, ArrayOfKeysOfT extends (keyof T)[]> {
    constructor(args: {[index in keyof ArrayOfKeysOfT]: T[ArrayOfKeysOfT[index]]}) {
        args;
    }
}

我得到的错误提示

  

类型ArrayOfKeysOfT[index]不能用于索引类型T

但是看起来这段代码应该没问题。我不确定这是设计使然还是Typescript中的错误。

更新

我意识到这里的问题是ArrayOfKeysOfT[index],其中index是类型keyof ArrayOfKeysOfT不仅导致包含ArrayOfKeysOfT的所有成员的类型,而且还包含一般情况下,数组的所有不同键(长度,推入,弹出等),这就是为什么不能将其用于键入T的原因。

我要完成的工作如下。

说我定义一些接口

interface Example {
    one: string;
    two: boolean;
}

那么应该允许

new Demo<Example, ['one', 'two']>({
    one: "some string",
    two: false
});

这应该导致编译器错误,因为类型参数数组中没有'two'

new Demo<Example, ['one']>({
    one: "some string",
    two: false
});

这应该导致编译器错误,因为三个不是第一个类型参数实参的键

new Demo<Example, ['one', 'two', 'three']>({
    one: 'some string',
    two: true,
    three: 4
});

最后这应该不起作用,因为分配给args对象中成员'two'的值是错误的类型

new Demo<Example, ['one', 'two']>({
    one: "some string",
    two: "another string"
});

1 个答案:

答案 0 :(得分:1)

class Demo<T, ArrayOfKeysOfT extends (keyof T)[]> {
    constructor(args: {[P in ArrayOfKeysOfT[number]]: T[P]}) {
        console.log(args);
    }
}

interface ABC {
    a: number;
    b: string;
    c: boolean;
}

const demo1 = new Demo<ABC, ['a', 'b']>({ 'a': 0, 'b': 'hi' }); // works!
const demo2 = new Demo<ABC, ['a', 'd']>({ 'a': 0, 'd': null }); // ERROR - Type '["a", "d"]' does not satisfy the constraint '("a" | "b" | "c")[]'
const demo3 = new Demo<ABC, ['c']>({ 'c': 'not a boolean' }); // ERROR - Type 'string' is not assignable to type 'boolean'.
const demo4 = new Demo<ABC, ['b', 'c']>({ 'a': 0 }); // ERROR - argument of type '{ 'a': number; }' is not assignable to parameter of type '{ b: string; c: boolean; }'.

我很乐意提供帮助!

更新

只是想提醒您(或让您知道),内置的Pick<T, K>工具类型存在于标准TypeScript库中,这使得Demo类型的排序变得多余:

let a: Pick<ABC, 'a' | 'b'> = {'a': 2, 'b': 'hello'};