首页 > 解决方案 > 定义类型以使用类型选择的键创建对象似乎被破坏

问题描述

为什么这不起作用?

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

我得到的错误说

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

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

更新

我意识到这里的问题是,类型结果ArrayOfKeysOfT[index]在哪里不仅包含 的所有成员,而且通常包含数组的所有不同键(长度、推送、弹出等),这就是为什么它不能用于键入 T。indexkeyof ArrayOfKeysOfTArrayOfKeysOfT

我想要完成的是以下内容。

说我定义了一些接口

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

那么这应该被允许

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

这应该会导致编译器错误,因为“两个”不在类型参数数组中

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"
});

标签: typescript

解决方案


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; }'.

我很乐意提供帮助!

更新

只是想提醒您(或让您知道)标准 TypeScript 库中存在内置Pick<T, K>实用程序类型,这使得Demo类型有点多余:

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

推荐阅读