我對變數“day”有一個型別斷言,因此當我為鍵分配布林值時,它不會引發任何錯誤。
我沒有這樣做,
const day: Day = 2
因為我得到的值是一個字串(這是一個動態值),我需要做一個型別斷言。
您能否檢查以下示例并建議需要更改哪些內容以使其引發錯誤?
type Day = 0 | 1 | 2;
type TTime = {
[K in Day]?: string
}
const day = 2 as Day;
const obj: TTime = {
[day]: true // Expect this to throw error as 'boolean is not assignable to key
}
我正在嘗試解決的另一個詳細示例。我必須獲取另一個物件的鍵(默認為 string[])并輸入 assertion。
type Day = 0 | 1 | 2;
type TTime = {
[K in Day]?: string
}
const result: TTime = {
2: 'I am result'
}
const keys = Object.keys(result);
let obj: TTime;
keys.forEach((key) => {
const k = key as unknown as Day;
const value = result[k]; //Key is string, so needs to be type asserted
obj = {
[k]: true //k is 2 in this case, but the value is boolean type and incorrect, this error
// is thrown when I remove the type assertion added and hardcode k as 2.
}
})
uj5u.com熱心網友回復:
這樣錯誤就會出現;
type Day = 0 | 1 | 2;
type TTime = {
[K in Day]?: string
}
const day: Day = 2;
const obj: TTime = {
[day]: true // Expect this to throw error as 'boolean is not assignable to key
}
uj5u.com熱心網友回復:
型別斷言day導致了這個問題。您不需要斷言(甚至不需要注釋):原語在 JavaScript 和 TypeScript 中是不可變的,因此通過使用const關鍵字宣告變數,數字將始終是文字型別2,TypeScript 無需額外語法就知道這一點。
TS游樂場
type Day = 0 | 1 | 2;
type TTime = { [K in Day]?: string };
// This is the same type as above, using some type utilities:
// https://www.typescriptlang.org/docs/handbook/utility-types.html
// type TTime = Partial<Record<Day, string>>;
// Don't use a type assertion here. (https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-assertions)
// If you prefer an annotation, you could write it this way:
// const day: Day = 2;
const day = 2;
const obj: TTime = {
[day]: true, /*
~~~~~
Type of computed property's value is 'boolean', which is not assignable to type 'string'.(2418) */
};
uj5u.com熱心網友回復:
不幸的是,您遇到了兩個 TypeScript 限制或錯誤……第一個是次要的,但它導致了主要的一個。
次要問題是microsoft/TypeScript#13948,其中具有聯合型別的計算屬性鍵的物件被賦予索引簽名,這不必要地將物件型別擴展為比您想要的不太有用的東西。例如:
const v = { [Math.random() < 0.5 ? "a" : "b"]: 123 };
// const v: { [x: string]: number;}
該值v將是{a: 123}或{b: 123}在運行時。因此,如果 TypeScript 將型別推斷為v類似于{a: number} | {b: number}. 相反,它推斷{ [x: string]: number }……就編譯器而言,它完全不知道鍵名v有什么;只是它確實具有的任何屬性都是 type number。
在你的情況下,你有
const obj = { [day]: true };
// const obj: { [x: number]: boolean; }
哪里obj已經??從某樣東西{0: boolean} | {1: boolean} | {2: boolean}一路拓寬到{[x: number]: boolean},已經完全忘記了Day。
這個問題不是災難性的,因為實際型別至少與所需型別兼容,但它不是最理想的。
第二個錯誤是microsoft/TypeScript#27144,其中具有索引簽名的物件型別可分配給具有所有可選屬性的型別,即使屬性值型別不兼容。這很糟糕:
const v: { [k: string]: number; } = {a: 1};
const x: { a?: string } = v; // no error!
的型別v具有索引簽名,其中所有屬性都必須具有number-type 值。同時,如果存在,則型別的型別x具有string-type 值的單個可選屬性。這些不應該被認為是兼容的,但它們是兼容的。因此,您可以在沒有編譯器警告的情況下錯誤地分配v給。x
在您的情況下,您有:
const p: TTime = o; // no error
其中TTime型別具有所有可選屬性,并且被認為與 的索引簽名型別兼容o,即使boolean和string不兼容。
呸。
所以這兩個問題的相互作用導致了你的問題。在這里要做的“正確”事情可能是等待/游說 microsoft/TypeScript#27144 得到修復。如果您想解決那個問題并給它一個??,那不會有什么壞處。它可能也不會有太大幫助。誰知道何時或什至會得到解決。
與此同時,你必須處理它。
一種方法是為 microsoft/TypeScript#13948 制定解決方法。我們可以撰寫一個輔助函式來直接斷言該值是更有用的型別,而不是滿足于索引簽名型別。像這樣:
const kv = <K extends PropertyKey, V>(
k: K, v: V
) => ({ [k]: v }) as { [P in K]: { [Q in P]: V } }[K];
該kv函式接受一個鍵和一個值,并生成一個物件,該物件具有對應于該鍵和值的一個屬性:
const y = kv("a", 123);
// const y: { a: number; }
如果我們在鍵是聯合型別時這樣做,我們會得到聯合型別的輸出:
const w = kv(Math.random() < 0.5 ? "a" : "b", 123);
// const w: {a: number} | {b: number}
所以你可以用它來制作obj:
const obj = kv(day, true);
// const obj: { 0: boolean; } | { 1: boolean; } | { 2: boolean; }
現在它obj沒有索引簽名,我們不會遇到 microsoft/TypeScript#27144:
const obj: TTime = kv(day, true); // error,
// boolean is not assignable to string
編譯器能夠根據需要看到{0: boolean} | {1: boolean} | {2: boolean}與 不兼容,TTime因為boolean與 不兼容string。
Playground 代碼鏈接
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/476051.html
標籤:javascript 打字稿
