采用以下代码
type PersonKeys = "name" | "age"
type PersonR = Record<PersonKeys, string>
const test = (human: Partial<PersonR>): PersonR => {
return {name: "", age: "", widen: true} // // fails perfect can't widen
}
const yolo = (k: PersonKeys) => {
return test(CreatePair(k, new Date())); // fails perfect, can't take anything but string
}
// Disgusting solution
const CreatePair = <T extends (number | string), A>(key: T, value: A): Record<T, A> => {
return {[key]: value} as any;
}
问题很简单,我希望返回PersonR的所有内容都不能扩大以获取非PersonR上的属性。
但是,我还希望任何需要PersonR的Partial只接受VALID的部分,这意味着{[K作为Keyof Person]:字符串},而不是{[K作为Keyof Person]:日期}
如果不使用CreatePair函数,这似乎是不可能的。
如果不使用CreatePair,能否使两个注释仍然失败? 为什么使用具有日期值的对象代替CreatePair不会导致其失败?
答案 0 :(得分:0)
问题很简单,我希望返回PersonR的所有内容都不能扩大以获取非PersonR上的属性。
TypeScript具有结构性。您可以随时添加属性。例如您的示例widen
可以很容易地分配:
type PersonKeys = "name" | "age"
type PersonR = Record<PersonKeys, string>
const test = {name: "", age: "", widen: true};
const fail: PersonR = test; // PASS
唯一出错的情况是直接赋值(这是return语句正在执行的操作)。
答案 1 :(得分:0)
根据我对您问题的理解,您想确保在调用test
时,参数仅具有PersonR
指定的键。所以这些都应该失败:
test({ [k]: new Date() }); // has a string indexer, because of the computed property
let o = { name: "", age: "", widen: true };
test(o); // not a direct assigment of an object literal, so this is allowed
没有通用的编译器切换到全局不允许这种情况。有人可以辩称,原则上不可能有这样的切换,因为在两种情况下,参数的类型都是参数类型的结构子类型,因此应在OOP规则下允许这样做。从OOP角度来看,怪异的检查是多余的属性检查,因为在这种情况下,我们无法将结构子类型分配给其超类型(基本上,在这种情况下,我们说let base:BaseType = new DerivedType()
是错误)。
在现实世界中所说的多余属性可能表示错误(因此,在编译器中实现了多余属性检查)。虽然我们不能全局禁止使用多余的属性,但可以使用条件类型禁止参数包含多余的属性。我们在函数中使用泛型类型参数以获取参数的实际类型,如果此参数类型具有多余的属性(或string
索引器),则会向参数类型添加字符串文字类型,这将触发错误:
type PersonKeys = "name" | "age"
type PersonR = Record<PersonKeys, string>
type StrictPropertyCheck<T, TExpected, TError> = Exclude<keyof T, keyof TExpected> extends never ? {} : TError;
const test = <T extends Partial<PersonR>>(human: T & StrictPropertyCheck<T, PersonR, "No extra properties!">): PersonR => {
return {name: "", age: "", widen: true} // // fails perfect can't widen
}
const yolo = (k: PersonKeys) => {
test({ [k]: new Date() }); // //error
let o = { name: "", age: "", widen: true };
test(o); // error
}