【发布时间】:2021-01-30 19:20:37
【问题描述】:
基本上我想要实现的是让 X 类从提供的构造函数参数类型推断其 K 类型。
我写了这个:
interface XContstructorParams<K extends string = never> {
record?: Record<K, number>;
// Other stuff with some being optionals, which is why it's all in single
// object, as I don't want to do new X(arg1, undefined, undefined, arg2)
}
class X<K extends string = never> {
private record: Record<K, number>;
constructor(params: XContstructorParams<K>) {
// I'd rather avoid to use a type assertion here but it's not a big deal
// compared to the issue below.
this.record = params.record || {} as Record<K, number>;
}
getNumber(k: K): number {
return this.record[k];
}
}
当没有给出record 属性时,这实际上可以推断 K 的类型为 never,但它不会阻止手动为 K 指定不正确的值:
// Correctly inferred to be X<'a', 'b'>
const x1 = new X({ record: {'a': 1, 'b': 2} });
// Correctly inferred to be X<never>
const x2 = new X({});
// Oops ! This is incorrect as `getNumber` will not return a number when called with 'c'
// or 'd ! But it is allowed because of how I wrote the constructor `record` property to
// be optional. I want it to be optional only when K is never. It's either you provided
// a record and it's keys determine K, or you didn't give a record and K is never, but
// should not be able to specify K and not provide a record matching your specified K.
const x3 = new X<'c' | 'd'>({});
我希望 x3 被识别为编译错误,但我无法让它工作。我做错了什么?
编辑:由于某种原因,堆栈溢出会在消息开头删除我的“你好”,所以......我猜迟到总比没有好......您好,感谢您的帮助! ;-)
【问题讨论】:
-
为什么不
class X<T extends Record<string, number> { getNumber(k: keyof T){} } -
感谢您的回复。我刚刚测试了您的建议,但
const x3 = new X<Record<'c' | 'd', number>>({});在这种情况下也不会抛出错误。 -
因为参数的
record属性是可选的,所以当参数中省略该属性时,它只是使用与显式类型参数对应的任何类型进行实例化 -
所以你是说我正在尝试做的事情(即得到 x3 的编译器错误)是不可能的?
-
它是可以通过几种方法之一确保引发错误,但我不完全确定为什么该属性是可选的。这似乎是一个矛盾。
constructor(params: XContstructorParams<K> = {record: {}})在 XContstructorParams` 中需要 record。
标签: typescript constructor optional record inference