【问题标题】:Defining type to create objects out of type's picked keys seems to be broken定义类型以使用类型选择的键创建对象似乎被破坏了
【发布时间】:2023-03-16 20:34:02
【问题描述】:

为什么这不起作用?

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

我得到的错误说

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

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

更新

我意识到这里的问题是ArrayOfKeysOfT[index] 其中indexkeyof 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"
});

【问题讨论】:

  • 如果我将它更改为T[ArrayOfKeysOfT[number]],我只能编译它,但这不考虑index。那么,请问您到底想达到什么目的?在您看来,args 应该是什么样子? index 不应该是 number 类型,因为 ArrayOfKeysOfTArray?我不太明白keyof ArrayOfKeysOfT 的用法,因为keyof any[] 会返回number | "length" | "toString" | "toLocaleString" | "pop" | "push" | "concat" | "join" | "reverse" | "shift" | "slice" | "sort" | "splice" | "unshift" | "indexOf" | "lastIndexOf" | ... 13 more ... | "values"
  • 好点。更新以包含更多上下文。

标签: typescript


【解决方案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; }'.

我很乐意提供帮助!

更新

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

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

【讨论】:

  • 太棒了!非常感谢!我将尝试为这个问题想一个更好的名字。如果您有任何建议,请告诉我。
  • @AjaxLeung 我会说“定义类型以使用类型选择的键创建对象似乎被破坏了”。另外,请参阅我的编辑。
  • 有道理。我不使用 Pick 的原因是因为我要在索引到 T 之后对类型做一些更复杂的事情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-22
  • 1970-01-01
  • 1970-01-01
  • 2021-11-26
  • 2020-11-08
  • 1970-01-01
相关资源
最近更新 更多