簡體   English   中英

輸入'字符串| number' 不可分配到類型 'never'

[英]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"] ... 寫什么是安全的? 只有oaob有效的東西......也就是說, (string | number) & (number | boolean) ,它(當你擺弄跨交叉點分布聯合和減少時)變成只是number 你只能安全地寫一個number

但是,在您的情況下,交集是string & string & number 不幸的是,沒有既是string又是number ……因此減少到never 哎呀。


為了解決這個問題,我可能會重構這段代碼,使list類型更窄,只允許“匹配” foobar屬性,然后向forEach方法傳遞一個通用回調,其中foobar被注釋,以便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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM