Версия TypeScript: 2.1.1
Код
type A = { a: string; }
type B = { b: string; }
type AorB = A | B;
declare const AorB: AorB;
if (AorB.a) {
// use AorB.a
}
Ожидаемое поведение:
Код компилируется без ошибок. Несмотря на то, что a
не (обязательно) существует на всех составляющих союза, тот факт, что он существует на некоторых, должен позволить мне проверить наличие .a
и использовать его, если он присутствует.
Фактическое поведение:
Typescript жалуется: «Свойство a не существует для типа AorB ... Свойство a не существует для типа B.»
В документе говорится:
Чтобы тот же код работал, нам нужно использовать утверждение типа:
let pet = getSmallPet();
if ((<Fish>pet).swim) {
(<Fish>pet).swim();
}
else {
(<Bird>pet).fly();
}
http://www.typescriptlang.org/docs/handbook/advanced-types.html
Тогда в вашем образце:
if ((<A>AorB).a) {
// use AorB.a
}
Проблема здесь в том, что поскольку B
не объявляет свойство a
, во время выполнения оно может иметь свойство a
любого возможного типа (поскольку вы можете назначить объект с любым набором свойств в B
если он имеет свойство b
типа string). Вы можете заставить его работать, явно объявив свойство a: undefined
в B
(таким образом гарантируя, что B
не будет иметь случайного свойства a
):
type A = { a: string; }
type B = { b: string; a: undefined }
type AorB = A | B;
declare const AorB: AorB;
if (AorB.a) {
// Ok
}
Имеет смысл. Мозг пердит.
Если вы определяете a: undefined
для типа B, вам нужно будет установить его в undefined
при создании / передаче переменной.
Чтобы обойти это, вы можете объявить a
как a?: undefined
, и машинописный текст будет счастлив, если вы его опустите.
Если я правильно понимаю комментарии, это должно сработать (но бросает; проверено на игровой площадке): это ошибка или нет? 🤔
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'
});
Я вообще этого не понимаю. Разве if ((<A>AorB).a)
то же самое, что использовать if (A.a)
потому что вы заставляете его снова набрать A
?
Если вы определяете
a: undefined
для типа B, вам нужно будет установить его вundefined
при создании / передаче переменной.
Чтобы обойти это, вы можете объявитьa
какa?: undefined
, и машинописный текст будет счастлив, если вы его опустите.
может быть лучше a?: never
, теперь нельзя присвоить undefined
по ошибке
Что, если вы не дадите имя каждому члену союза? (я не могу сделать утверждение типа, как указано выше, без имени для утвержденного типа?)
type u = "str" | {prop:"val"};
function f(arg:u){return arg.prop} // TypeScript: Property 'prop' does not exist on type 'u'
Любое решение?
я нахожу решение в книге:
interface A { x: number;}
interface B { y: string;}
function doStuff ( q: A | B ) {
if ( 'x' in q) {
// if type A...
}
else {
// if type B...
}
}
Выдержка из: Басарат Али Сайед. «Глубокое погружение в TypeScript». Apple Книги.
свойство объекта и может использоваться в качестве защиты типа, а TypeScript может знать, какой тип вы использовали.
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
};
});
});
Проблема здесь в том, что поскольку
B
не объявляет свойствоa
, во время выполнения оно может иметь свойствоa
любого возможного типа (поскольку вы можете назначить объект с любым набором свойств вB
если он имеет свойствоb
типа string). Вы можете заставить его работать, явно объявив свойствоa: undefined
вB
(таким образом гарантируя, чтоB
не будет иметь случайного свойстваa
):type A = { a: string; } type B = { b: string; a: undefined } type AorB = A | B; declare const AorB: AorB; if (AorB.a) { // Ok }
У меня не работает 07.10.2020
И я считаю, что такое поведение TS нехорошо, потому что оно мало помогает разработчику ...
Самый полезный комментарий
я нахожу решение в книге:
Выдержка из: Басарат Али Сайед. «Глубокое погружение в TypeScript». Apple Книги.
свойство объекта и может использоваться в качестве защиты типа, а TypeScript может знать, какой тип вы использовали.