TypeScript Version: 2.1.1
Code
type A = { a: string; }
type B = { b: string; }
type AorB = A | B;
declare const AorB: AorB;
if (AorB.a) {
// use AorB.a
}
Expected behavior:
The code compiles without errors. Even though a
doesn't (necessarily) exist on all the constituents of the union, the fact that it exists on some should allow me to check for .a
and use it if it is present.
Actual behavior:
Typescript complains: "Property a does not exist on type AorB... Property a does not exist on type B."
The doc says :
To get the same code working, we’ll need to use a type assertion:
let pet = getSmallPet();
if ((<Fish>pet).swim) {
(<Fish>pet).swim();
}
else {
(<Bird>pet).fly();
}
http://www.typescriptlang.org/docs/handbook/advanced-types.html
Then in your sample:
if ((<A>AorB).a) {
// use AorB.a
}
The issue here is that because B
doesn't declare an a
property, it might at run-time have an a
property of any possible type (because you can assign an object with any set of properties to a B
as long as it has a b
property of type string). You can make it work explicitly declaring an a: undefined
property in B
(thus ensuring that B
won't have some random a
property):
type A = { a: string; }
type B = { b: string; a: undefined }
type AorB = A | B;
declare const AorB: AorB;
if (AorB.a) {
// Ok
}
Makes perfect sense. Brain fart.
If you define a: undefined
on type B, you'll have to set it to undefined
when you create/pass a variable.
To get around that, you can declare a
as a?: undefined
, and typescript will be happy if you omit it.
If I understand the comments correctly, this should work (but throws; tested on playground): Is this a bug or not? 🤔
type LinkProps = {
to: string;
onClick?: undefined;
// Link specific props:
target: string;
}
type ButtonProps = {
to?: undefined;
onClick: Function;
// Button specific props:
disabled: boolean;
}
type ActionProps = LinkProps | ButtonProps;
const Action = (props: ActionProps) =>
props.to ?
'Link with target: ' + props.target // Error not on ButtonProps
:
'Button with disabled: ' + props.disabled; // Error: not on LinkProps
Action({
to: 'dssd',
target: '_blank'
});
I don't understand this at all. Isn't if ((<A>AorB).a)
the same as using if (A.a)
because you're forcing it back to type A
?
If you define
a: undefined
on type B, you'll have to set it toundefined
when you create/pass a variable.
To get around that, you can declarea
asa?: undefined
, and typescript will be happy if you omit it.
might be better a?: never
, now you can not assign undefined
by mistake
What if you don't give a name to each of the members of the union? (can't make a type assertion as above without a name for the asserted type, can I?)
type u = "str" | {prop:"val"};
function f(arg:u){return arg.prop} // TypeScript: Property 'prop' does not exist on type 'u'
Any solution?
i find a solution on book :
interface A { x: number;}
interface B { y: string;}
function doStuff ( q: A | B ) {
if ( 'x' in q) {
// if type A...
}
else {
// if type B...
}
}
Excerpt From: Basarat Ali Syed. “TypeScript Deep Dive.” Apple Books.
a property on an object and can be used as a type guard, and the TypeScript can know which type you used.
type ColorItemType = {
colorId: number,
colorName: string,
}
type NumItemType = {
numId: number,
numName: string
}
type ResType = {
itemId: number,
// 0 color 1 num
type: number,
itemInfo: {
colorList: Array<ColorItemType>
numList: Array<NumItemType>
}
}
const request = () => {
return [{
itemId: 1,
type: 0,
itemInfo: {
colorList: [{
colorId: 1,
colorName: 'blue'
}],
numList: []
}
}];
};
const dataSource: Array<ResType> = request();
const formatData = dataSource.map(dataItem => {
const list: Array<ColorItemType | NumItemType> = dataItem.type === 1 ? dataItem.itemInfo.numList : dataItem.itemInfo.colorList;
return list.map(listItem => {
return {
// An error will be reported here
value: listItem.numId || listItem.colorId,
label: listItem.numName || listItem.colorName
};
});
});
The issue here is that because
B
doesn't declare ana
property, it might at run-time have ana
property of any possible type (because you can assign an object with any set of properties to aB
as long as it has ab
property of type string). You can make it work explicitly declaring ana: undefined
property inB
(thus ensuring thatB
won't have some randoma
property):type A = { a: string; } type B = { b: string; a: undefined } type AorB = A | B; declare const AorB: AorB; if (AorB.a) { // Ok }
Does not work for me 07.10.2020
And I think that this behavior of TS is not good because it does not help a developer much...
Most helpful comment
i find a solution on book :
Excerpt From: Basarat Ali Syed. “TypeScript Deep Dive.” Apple Books.
a property on an object and can be used as a type guard, and the TypeScript can know which type you used.