我试图在events上产生一个Klass属性,该属性包含与给定接口(interface)的所有键完全匹配的字符串数组。像这样:

interface Events {
    one: (foo: string) => void
    two: (bar: number) => void
}

class Klass {
    protected readonly events: [keyof Events] = ['one', 'two']
}

但是,上述错误与以下内容有关:
[ts]
Type '["one", "two"]' is not assignable to type '["one" | "two"]'.
  Types of property 'length' are incompatible.
    Type '2' is not assignable to type '1'. [2322]
(property) Klass.events: ["one" | "two"]

为了确保events属性返回包含所有事件的数组,这里需要做些什么?

最佳答案

您几乎可以使用conditional types在类型系统(假设为TS3.0 +)中表达这一点,但要注意以下几点:

type Invalid<T> = ["Needs to be all of", T]
const arrayOfAll = <T>() => <U extends T[]>(
  ...array: U & ([T] extends [U[number]] ? unknown : Invalid<T>[])
) => array;
const arrayOfAllEventKeys = arrayOfAll<keyof Events>();

const goodEvents = arrayOfAllEventKeys('one', 'two'); // okay, type ['one', 'two']

const extraEvents = arrayOfAllEventKeys('one', 'two', 'three'); // error
//                                                    ~~~~~~~
// Argument of type "three" is not assignable to parameter of type "one" | "two"

const missingEvents = arrayOfAllEventKeys('one'); // error
//                                        ~~~~~
// Argument of type "one" is not assignable to
// parameter of type ["Needs to be all of", "one" | "two"]

const redundantEvents = arrayOfAllEventKeys('one', 'two', 'one'); // no error
// doesn't enforce distinctness

请注意,推断goodEvents的类型为['one', 'two'],并且没有错误。那就是你想要的。您会在其他事件和丢失事件上出错。

注意事项1:丢失事件的错误有点神秘; TypeScript尚不支持custom error messages,因此我选择了一些希望可以理解的东西(Argument of type "one" is not assignable to parameter of type ["Needs to be all of", "one" | "two"])。

注意事项2:冗余事件没有错误。我没有找到一种通用的方法来要求arrayOfAllEventKeys的每个参数都具有不与issues with recursive types冲突的独特类型。可以使用重载或其他类似技术来处理长度达到一定硬编码长度(例如10)的数组,但是我不知道这是否满足您的需求。让我知道。

希望能有所帮助;祝你好运!

关于typescript - 如何确保数组的值是TypeScript接口(interface)的键?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53387838/

10-12 15:25
查看更多