Typescript: すべてのユニオンメンバーで定義されていないプロパティの場合、オブジェクトタイプのユニオンでプロパティにアクセスできません

作成日 2016年12月10日  ·  12コメント  ·  ソース: microsoft/TypeScript

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に存在しません。」と文句を言います。

Question

最も参考になるコメント

私は本で解決策を見つけます:

interface A { x:  number;} 
interface B { y:  string;}
function doStuff ( q: A | B ) {
  if ( 'x'  in q) {
    //  if type A...
  }
  else {
    // if type B...
  }
}

抜粋:Basarat AliSyed。 「TypeScriptディープダイブ。」 アップルブックス。

オブジェクトのプロパティであり、タイプガードとして使用でき、TypeScriptは使用したタイプを認識できます。

全てのコメント12件

ドキュメントによると:

同じコードを機能させるには、型アサーションを使用する必要があります。

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
}

ここでの問題は、 Baプロパティを宣言していないため、実行時に任意のタイプのaプロパティが存在する可能性があることです(文字列型のbプロパティがある限り、 Bへのプロパティのセットを持つオブジェクト)。 B a: undefinedプロパティを明示的に宣言して機能させることができます(したがって、 Bにランダムなaプロパティがないことを確認します)。

type A = { a: string; } 
type B = { b: string; a: undefined }
type AorB = A | B;

declare const AorB: AorB;

if (AorB.a) {
    // Ok
}

完全に理にかなっています。 脳のおなら。

タイプBでa: undefinedを定義する場合、変数を作成/渡すときにundefinedに設定する必要があります。
これを回避するには、 aa?: undefinedとして宣言できます。これを省略した場合、typescriptは問題ありません。

コメントを正しく理解していれば、これは機能するはずです(ただし、スローされます。遊び場でテストされます):これはバグですか? 🤔

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)は、 Aと入力するように強制しているため、 (A.a)場合と同じではありませんか?

タイプBでa: undefinedを定義する場合、変数を作成/渡すときにundefinedに設定する必要があります。
これを回避するには、 aa?: undefinedとして宣言できます。これを省略した場合、typescriptは問題ありません。

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...
  }
}

抜粋:Basarat AliSyed。 「TypeScriptディープダイブ。」 アップルブックス。

オブジェクトのプロパティであり、タイプガードとして使用でき、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
        };
    });
});

ここでの問題は、 Baプロパティを宣言していないため、実行時に任意のタイプのaプロパティが存在する可能性があることです(文字列型のbプロパティがある限り、 Bへのプロパティのセットを持つオブジェクト)。 B a: undefinedプロパティを明示的に宣言して機能させることができます(したがって、 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の動作は、開発者の役に立たないため、良くないと思います...

このページは役に立ちましたか?
5 / 5 - 1 評価