1 回答

TA貢獻(xiàn)1780條經(jīng)驗(yàn) 獲得超5個(gè)贊
有幾件事導(dǎo)致這種情況發(fā)生。這里的主要問(wèn)題是 TypeScript 不支持嵌套的可區(qū)分聯(lián)合。在microsoft/TypeScript#18758有一個(gè)相當(dāng)古老的開(kāi)放建議;如果您對(duì)此非常關(guān)心,您可能想去那里給它一個(gè)??,或者如果它特別引人注目,請(qǐng)描述您的用例。不過(guò),就目前而言,它還不是語(yǔ)言的一部分。這意味著,這樣的代碼會(huì)成功:
type Discrim = { a: 0, c: string } | { a: 1, c: number };
declare const d: Discrim;
d.a === 0 ? d.c.toUpperCase() : d.c.toFixed(); // okay
但是這樣的代碼失敗了:
type NestedDiscrim = { a: { b: 0 }, c: string } | { a: { b: 1 }, c: number };
declare const n: NestedDiscrim;
n.a.b === 0 ? n.c.toUpperCase() : n.c.toFixed(); // error!
因?yàn)樵谇罢咧?,Discrim編譯器將其視為帶有a屬性作為判別式的可區(qū)分聯(lián)合,但在后者中,NestedDiscrim不將其視為帶有a屬性作為判別式的可區(qū)分聯(lián)合。
同樣,在您的情況下,Kind是受歧視的工會(huì),但ExCThingy | CThingy不是。
對(duì)于編譯器視為可區(qū)分聯(lián)合的類型,從 TypeScript 3.5 開(kāi)始,添加了對(duì)如下賦值的支持:
const k: Kind = { kind: Math.random() < 0.5 ? "A" : Math.random() < 0.5 ? "B" : "C" }; // okay
分配給的對(duì)象的k類型{kind: "A" | "B" | "C"}在技術(shù)上不可分配給受歧視聯(lián)合的任何單個(gè)成員Kind,這是您在 TS3.4 及以下版本中遇到的錯(cuò)誤:
// Type '{ kind: "A" | "B" | "C"; }' is not assignable to type 'Kind'.
但是在 TS3.5 及更高版本中,編譯器會(huì)進(jìn)行額外的檢查以獲取具有聯(lián)合類型判別屬性的單個(gè)對(duì)象類型,并將聯(lián)合向上傳播到具有單類型判別屬性的對(duì)象類型的聯(lián)合中。這樣就可以編譯了。
不幸的是,正如我們所提到的,ExCThingy | CThingy根據(jù)編譯器,它不是一個(gè)有區(qū)別的聯(lián)合。上述支持僅適用于受歧視的工會(huì)。對(duì)于非歧視工會(huì),你會(huì)得到同樣的錯(cuò)誤:
type NotDiscrim = { a: string } | { a: number };
const x: NotDiscrim = { a: Math.random() < 0.5 ? "" : 1 }; // error in all versions of TS
// Type '{ a: string | number; }' is not assignable to type 'NotDiscrim'
編譯器根本不對(duì)非區(qū)分聯(lián)合執(zhí)行聯(lián)合傳播分析。并且由于ExCThingy | CThingy不被認(rèn)為是有區(qū)別的聯(lián)合,因此 type 的值{ foo: Kind, something: 'test', somethingelse: 'test2' }不被認(rèn)為是 type ExCThingy | CThingy。
所以這就是正在發(fā)生的事情。要在此處繼續(xù),您可能需要使用類型斷言來(lái)告訴編譯器您確定您正在做的事情是安全的:
fooArray.map(e => DoSomething({
foo: e.foo,
something: 'test',
somethingelse: 'test2'
} as ExCThingy | CThingy)); // no error
要么,要么將單個(gè)對(duì)象拆分為編譯器可以實(shí)際檢查的聯(lián)合,如下所示:
fooArray.map(e => DoSomething(e.foo.kind === "C" ?
{ foo: e.foo, somethingelse: 'test2' } : { foo: e.foo, something: 'test' }
));
添加回答
舉報(bào)