基本上我想要实现的是让类 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 识别为编译错误,但我无法使其正常工作。我做错了什么?
编辑:出于某种原因,堆栈溢出在消息的开头删除了我的“你好”,所以......我猜迟到总比没有好......你好,感谢您的帮助! ;-)
答案 0 :(得分:0)
此解决方案适合您吗?
interface XContstructorParams<K extends string = never> {
record: K extends never ? undefined : 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 don't think you need type castin here
this.record = params.record
}
getNumber(k: K): number {
return this.record[k];
}
}
// Correctly inferred to be X<'a', 'b'>
const x1 = new X({ record: { 'a': 1, 'b': 2 } });
const result = x1.getNumber('a') // number
const x2 = new X<never>({}); // error
const x3 = new X<'c' | 'd'>({}); // error