[英]Type 'string | number' is not assignable to type 'never'
我想將list
的鍵和值動態映射到obj
。 但是,TS 給了我一條錯誤消息:
Type 'string | number' is not assignable to type 'never'
我不知道出了什么問題。 下面是代碼片段:
interface T {
// uncomment the next line makes the error go away
// [k: string]: any
a: string;
b?: string;
c?: number;
}
const obj: T = {
a: 'something',
};
const list: Array<{
foo: keyof T;
bar: string | number;
}> = [
{ foo: 'b', bar: 'str' },
{ foo: 'c', bar: 1 },
];
list.forEach(item => {
const { foo, bar } = item;
// The error message comes from the next line
obj[foo] = bar;
});
我注意到,如果我在interface T
包含輸入[k: string]: any
,錯誤消息就會消失。
但是,我不願意這樣做,因為我可以將其他鍵/值對添加到obj
,例如obj.d = 'error'
而沒有 TS 警告我。
另外,我很好奇為什么 TS 會給我這個錯誤消息,以及類型never
thing 是什么。
對於tsconfig.json
,我通過運行tsc --init
version 3.5.1
來使用默認值
謝謝你。
TypeScript 3.5 關閉了一個漏洞,即未正確檢查鍵聯合上的索引訪問寫入。 如果我有一個T
類型的對象obj
和一個泛型類型keyof T
的鍵foo
,那么雖然你可以安全地從obj[foo]
讀取一個T[keyof T]
類型的屬性,比如const baz: T[keyof T] = obj[foo]
,寫這樣的屬性可能不安全,比如const bar: T[keyof T] = ...; obj[foo] = bar;
const bar: T[keyof T] = ...; obj[foo] = bar;
在您的代碼中, foo
可能是"a"
而bar
可能是1
,這樣寫是不安全的。
漏洞被關閉的方式:如果我從鍵的聯合中讀取一個值,它會變成屬性類型的聯合,就像以前一樣。 但如果我寫一個值鍵的結合,它成為物業類型的交集。 所以說我有一個類型為{a: string | number, b: number | boolean}
的對象o
{a: string | number, b: number | boolean}
{a: string | number, b: number | boolean}
並且我想給o[Math.random()<0.5 ? "a" : "b"]
寫點東西o[Math.random()<0.5 ? "a" : "b"]
o[Math.random()<0.5 ? "a" : "b"]
... 寫什么是安全的? 只有對oa
和ob
都有效的東西......也就是說, (string | number) & (number | boolean)
,它(當你擺弄跨交叉點分布聯合和減少時)變成只是number
。 你只能安全地寫一個number
。
但是,在您的情況下,交集是string & string & number
。 不幸的是,沒有既是string
又是number
……因此減少到never
。 哎呀。
為了解決這個問題,我可能會重構這段代碼,使list
類型更窄,只允許“匹配” foo
和bar
屬性,然后向forEach
方法傳遞一個通用回調,其中foo
和bar
被注釋,以便obj[foo]
和bar
被視為相同的類型:
type KV = { [K in keyof T]-?: { foo: K, bar: NonNullable<T[K]> } }[keyof T]
/* type KV = {
foo: "a";
bar: string;
} | {
foo: "b";
bar: string;
} | {
foo: "c";
bar: number;
} */
const list: Array<KV> = [
{ foo: 'b', bar: 'str' },
{ foo: 'c', bar: 1 },
];
list.forEach(<K extends keyof T>(item: { foo: K, bar: NonNullable<T[K]> }) => {
const { foo, bar } = item;
obj[foo] = bar; // okay
});
KV
類型對映射和查找類型進行了一些類型處理,以生成所有可接受的foo
/ bar
對的聯合,您可以通過在KV
定義上使用 IntelliSense 進行驗證。
並且forEach()
回調作用於item: { foo: K, bar: NonNullable<T[K]> }
類型的值,用於泛型K extends keyof T
。 因此obj[foo]
將被視為類型T[K]
,您將為它分配一個NonNullable<T[K]>
, 根據不太合理但足夠方便的規則,這是可以接受的.
那有意義嗎? 希望有所幫助; 祝你好運!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.