簡體   English   中英

Typescript - 具有無效值的類型斷言不會引發錯誤

[英]Typescript - type assertion with invalid value is not throwing error

我對變量“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.
    }
})

不幸的是,您遇到了兩個 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}就好了。 {a: number} | {b: number} 相反,它推斷{ [x: string]: number } ... 就編譯器而言,它完全不知道v有什么鍵名; 只是它確實具有的任何屬性都是number類型。

在你的情況下,你有

const obj = { [day]: true };
// const obj: { [x: number]: boolean; }

其中obj已從{0: boolean} | {1: boolean} | {2: boolean} {0: boolean} | {1: boolean} | {2: boolean} {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類型的值。 同時, x的類型具有string類型值的單個可選屬性(如果存在)。 這些不應該被認為是兼容的,但它們是兼容的。 因此,您可以在沒有編譯器警告的情況下錯誤地將v分配給x

在您的情況下,您有:

const p: TTime = o; // no error

其中TTime類型具有所有可選屬性,並且被認為與o的索引簽名類型兼容,即使booleanstring不兼容。

呸。


所以這兩個問題的相互作用導致了你的問題。 在這里要做的“正確”事情可能是等待/游說 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} {0: boolean} | {1: boolean} | {2: boolean} {0: boolean} | {1: boolean} | {2: boolean}TTime不兼容,因為booleanstring不兼容,如所願。

Playground 代碼鏈接

這樣錯誤就會出現;


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
}

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) */
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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