我正在嘗試撰寫一個小函式來將兩個相同型別的物件合并到第三個相同型別的物件中,但是我遇到了打字問題。
這是我的情況的一個例子(也在TS Playground上):
interface IndividualDto {
firstnames: string[];
birthdates: Date[];
}
function mergeIndividuals(
individual1: IndividualDto,
individual2: IndividualDto
): IndividualDto {
const mergedIndividual: IndividualDto = { firstnames: [], birthdates: []};
const arrayProperties = [
"firstnames",
"birthdates",
] as const;
arrayProperties.forEach((property) => {
mergedIndividual[property] = [...individual1[property], ...individual2[property]];
});
return mergedIndividual;
}
我的想法是以相同的方式處理所有這些屬性,并以另一種方式處理其他屬性(此處不相關。)
但是,使用此代碼時,我會遇到以下錯誤mergedIndividual[property]:
Type '(string | MilDate)[]' is not assignable to type 'string[] & MilDate[]'.
Type '(string | MilDate)[]' is not assignable to type 'string[]'.
Type 'string | MilDate' is not assignable to type 'string'.
Type 'MilDate' is not assignable to type 'string'.
TypeScript 似乎無法理解,因為這三個物件的型別相同,并且我參考的是相同的屬性,所以它們都兼容賦值。
Also, I would like to explicitly type arrayProperties so that I cannot add strings which are not keys of IndividualDto. I've tried using const arrayProperties: readonly (keyof IndividualDto)[] but it's less specific than the string union and creates other errors related to other properties not being array types.
uj5u.com熱心網友回復:
問題是 TypeScript 不知道哪些屬性property名稱,只是它是屬性之一IndividualDto(如果您正確鍵入陣列)。所以mergedIndividual[property]以 type 結束string[] & MilDate[],當然你不能分配任何東西。
您可以拆分IndividualDto為兩個介面(然后您可以將它們組合成一個IndividualDto型別),其中所有屬性的型別都相同。例如:
// The properties that are `string[]`
interface IndividualDtoStringArrays {
firstnames: string[];
lastnames: string[];
}
// The properties that are `MilDate[]`
interface IndividualDtoMilDateArrays {
birthDates: MilDate[];
}
// The overall type
type IndividualDto = IndividualDtoStringArrays & IndividualDtoMilDateArrays;
這樣,您可以使用兩個單獨的陣列,并且 TypeScript 很高興,因為沒有型別歧義:
function mergeIndividuals(
individual1: IndividualDto,
individual2: IndividualDto
): IndividualDto {
const mergedIndividual = emptyIndividualDto();
const stringArrayProperties: readonly (keyof IndividualDtoStringArrays)[] = [
"firstnames",
"lastnames",
// ...
];
const milDateArrayProperties: readonly (keyof IndividualDtoMilDateArrays)[] = [
"birthDates",
// ...
];
for (const property of stringArrayProperties) {
mergedIndividual[property] = [...individual1[property], ...individual2[property]];
}
for (const property of milDateArrayProperties) {
mergedIndividual[property] = [...individual1[property], ...individual2[property]];
}
return mergedIndividual;
}
游樂場鏈接
Alternatively: This is a small, well-contained utility function, and even though TypeScript doesn't know the assignment is valid, you do. So you might just go for error suppression via ts-ignore:
function mergeIndividuals(
individual1: IndividualDto,
individual2: IndividualDto
): IndividualDto {
const mergedIndividual = emptyIndividualDto();
const arrayProperties: readonly (keyof IndividualDto)[] = [
"firstnames",
"lastnames",
"birthDates",
];
for (const property of arrayProperties) {
// @ts-ignore
mergedIndividual[property] = [...individual1[property], ...individual2[property]];
}
return mergedIndividual;
}
Playground link
Error suppression, like type assertion, is best avoided. Your object looks like it just has a couple of types of properties, so I'd probably go with the first solution (separate loops). But this is a viable option in a small, well-contained function like this one.
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/439045.html
標籤:typescript
