ide*_*xer 6 generics generic-programming typescript keyof
我尝试编写一个泛型函数,汇总数据库更新的更新数据.
传递参数:
即使我使用限制键的类型keyof R,我也不能将具有该键的新对象分配给Partial<R>常量.我收到错误我该Type '{ [x: string]: any[]; }' is not assignable to type 'Partial<R>'.怎么做才能使下面的代码工作?如果我用R非泛型类型替换泛型类型,它可以工作.但这不是我需要的.
interface BaseRecord {
readonly a: ReadonlyArray<string>
}
function getUpdateData<R extends BaseRecord>(record: R, key: keyof R, newItem: string) {
const updateData: Partial<R> = { [key]: [...record[key], newItem] }
return updateData
}
interface DerivedRecord extends BaseRecord {
readonly b: ReadonlyArray<string>
readonly c: ReadonlyArray<string>
}
const record: DerivedRecord = { a: [], b: [], c: ["first item in c"] }
console.log(getUpdateData<DerivedRecord>(record, "c", "second item in c"))
Run Code Online (Sandbox Code Playgroud)
jca*_*alz 10
您总是可以通过狡猾(例如,索引访问和假设R[key]是读写的编译器)将类型系统弯曲到您的意愿
function getUpdateData<R extends BaseRecord>(record: R, key: keyof R, newItem: string) {
var updateData: Partial<R> = {};
updateData[key] = [...record[key], newItem];
return updateData
}
Run Code Online (Sandbox Code Playgroud)
或蛮力(通过any类型):
function getUpdateData<R extends BaseRecord>(record: R, key: keyof R, newItem: string) {
const updateData: Partial<R> = <any> { [key]: [...record[key], newItem] }
return updateData
}
Run Code Online (Sandbox Code Playgroud)
以上回答了你的问题,但要小心:这个功能不安全.它假定任何record传入将具有string[]该key属性的值,但类型R可能不会.例如:
interface EvilRecord extends BaseRecord {
e: number;
}
var evil: EvilRecord = { a: ['hey', 'you'], e: 42 };
getUpdateData(evil, 'e', 'kaboom'); // compiles okay but runtime error
Run Code Online (Sandbox Code Playgroud)
此外,返回值类型Partial<R>有点过宽:您知道它将具有key密钥,但您需要检查类型系统是否满意:
var updatedData = getUpdateData<DerivedRecord>(record, "c", "first item in c") // Partial<DerivedRecord>
updatedData.c[0] // warning, object is possibly undefined
Run Code Online (Sandbox Code Playgroud)
我建议输入getUpdateData()如下:
type KeyedRecord<K extends string> = {
readonly [P in K]: ReadonlyArray<string>
};
function getUpdateData<K extends string, R extends KeyedRecord<K>=KeyedRecord<K>>(record: R, key: K, newItem: string) {
return <KeyedRecord<K>> <any> {[key as string]: [...record[key], newItem]};
}
Run Code Online (Sandbox Code Playgroud)
(注意,由于TypeScript中的错误,这仍然很难正确输入)现在该函数只接受key属性类型的东西ReadonlyArray<string>,并保证key属性存在于返回值中:
var evil: EvilRecord = { a: ['hey', 'you'], e: 42 };
getUpdateData(evil, 'e', 'kaboom'); // error, number is not a string array
var updatedData = getUpdateData(record, "c", "first item in c") // KeyedRecord<"c">
updatedData.c[0] // no error
Run Code Online (Sandbox Code Playgroud)
希望有所帮助.
我将getUpdateData()上面建议的声明更改为有两个通用参数,因为由于某些原因,TypeScript在推断key参数之前的类型太宽,迫使您在调用站点指定键类型:
declare function oldGetUpdateData<K extends string>(record: KeyedRecord<K>, key: K, newItem: string): KeyedRecord<K>;
oldGetUpdateData(record, "c", "first item in c"); // K inferred as 'a'|'b'|'c', despite the value of 'c'
oldGetUpdateData<'c'>(record, "c", "first item in c"); // okay now
Run Code Online (Sandbox Code Playgroud)
通过添加第二个泛型,我显然在正确推断出键类型之后延迟了TypeScript对记录类型的推断:
getUpdateData(record, "c", "hello"); // K inferred as 'c' now
Run Code Online (Sandbox Code Playgroud)
随意忽略这一点,但这就是香肠是如何用启发式推理制作的.
常量声明不能是泛型类型。
所以你的代码更改将是
function getUpdateData<R extends BaseRecord>(record: R, key: keyof R, newItem: string) {
const updateData:Partial<DerivedRecord> = {
[key]: [...record[key], newItem]
};
Run Code Online (Sandbox Code Playgroud)
或者
function getUpdateData<R extends BaseRecord>(record: R, key: keyof R, newItem: string) {
const updateData = {
[key]: [...record[key], newItem]
};
Run Code Online (Sandbox Code Playgroud)
或者
function getUpdateData<R extends BaseRecord>(record: R, key: keyof R, newItem: string) {
type PartRecord = Partial<DerivedRecord>;
const updateData: PartRecord = {
[key]: [...record[key], newItem]
};
return updateData;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2823 次 |
| 最近记录: |