Versão TypeScript: 2.1.1
Código
type A = { a: string; }
type B = { b: string; }
type AorB = A | B;
declare const AorB: AorB;
if (AorB.a) {
// use AorB.a
}
Comportamento esperado:
O código é compilado sem erros. Mesmo que a
não exista (necessariamente) em todos os constituintes do sindicato, o fato de existir em alguns deve permitir-me verificar se há .a
e usá-lo se estiver presente.
Comportamento real:
O texto datilografado reclama: "A propriedade a não existe no tipo AorB ... A propriedade a não existe no tipo B."
O doc diz:
Para fazer o mesmo código funcionar, precisaremos usar uma declaração de tipo:
let pet = getSmallPet();
if ((<Fish>pet).swim) {
(<Fish>pet).swim();
}
else {
(<Bird>pet).fly();
}
http://www.typescriptlang.org/docs/handbook/advanced-types.html
Então, em sua amostra:
if ((<A>AorB).a) {
// use AorB.a
}
O problema aqui é que, como B
não declara uma propriedade a
, pode em tempo de execução ter uma propriedade a
de qualquer tipo possível (porque você pode atribuir um objeto com qualquer conjunto de propriedades para um B
, desde que tenha uma propriedade b
do tipo string). Você pode fazer funcionar explicitamente declarando uma propriedade a: undefined
em B
(garantindo assim que B
não terá alguma propriedade a
aleatória):
type A = { a: string; }
type B = { b: string; a: undefined }
type AorB = A | B;
declare const AorB: AorB;
if (AorB.a) {
// Ok
}
Faz todo o sentido. Peido de cérebro.
Se você definir a: undefined
no tipo B, você terá que defini-lo para undefined
ao criar / passar uma variável.
Para contornar isso, você pode declarar a
como a?: undefined
, e o texto digitado ficará feliz se você omiti-lo.
Se entendi os comentários corretamente, isso deve funcionar (mas joga; testado no playground): Isso é um bug ou não? 🤔
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'
});
Eu não entendo nada disso. if ((<A>AorB).a)
o mesmo que usar if (A.a)
porque você o está forçando de volta para digitar A
?
Se você definir
a: undefined
no tipo B, você terá que defini-lo paraundefined
ao criar / passar uma variável.
Para contornar isso, você pode declarara
comoa?: undefined
, e o texto digitado ficará feliz se você omiti-lo.
pode ser melhor a?: never
, agora você não pode atribuir undefined
por engano
E se você não der um nome a cada um dos membros do sindicato? (não posso fazer uma declaração de tipo como acima sem um nome para o tipo declarado, posso?)
type u = "str" | {prop:"val"};
function f(arg:u){return arg.prop} // TypeScript: Property 'prop' does not exist on type 'u'
Qualquer solução?
eu encontro uma solução no livro:
interface A { x: number;}
interface B { y: string;}
function doStuff ( q: A | B ) {
if ( 'x' in q) {
// if type A...
}
else {
// if type B...
}
}
Trecho de: Basarat Ali Syed. “Mergulho Profundo de TypeScript.” Livros da Apple.
uma propriedade em um objeto e pode ser usada como uma proteção de tipo, e o TypeScript pode saber qual tipo você usou.
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
};
});
});
O problema aqui é que, como
B
não declara uma propriedadea
, pode em tempo de execução ter uma propriedadea
de qualquer tipo possível (porque você pode atribuir um objeto com qualquer conjunto de propriedades para umB
, desde que tenha uma propriedadeb
do tipo string). Você pode fazer funcionar explicitamente declarando uma propriedadea: undefined
emB
(garantindo assim queB
não terá alguma propriedadea
aleatória):type A = { a: string; } type B = { b: string; a: undefined } type AorB = A | B; declare const AorB: AorB; if (AorB.a) { // Ok }
Não funciona para mim 10.07.2020
E eu acho que esse comportamento do TS não é bom porque não ajuda muito um desenvolvedor ...
Comentários muito úteis
eu encontro uma solução no livro:
Trecho de: Basarat Ali Syed. “Mergulho Profundo de TypeScript.” Livros da Apple.
uma propriedade em um objeto e pode ser usada como uma proteção de tipo, e o TypeScript pode saber qual tipo você usou.