479

この質問は、 TypeScript を使用したクラス型チェックに直接類似しています

タイプ any の変数がインターフェイスを実装しているかどうかを実行時に確認する必要があります。これが私のコードです:

interface A{
    member:string;
}

var a:any={member:"foobar"};

if(a instanceof A) alert(a.member);

このコードを typescript プレイグラウンドに入力すると、最後の行に「名前 A は現在のスコープに存在しません」というエラーとしてマークされます。名前は現在のスコープに存在します。var a:A={member:"foobar"};エディターからの苦情なしで変数宣言を変更することもできます。Web を閲覧して SO に関する他の質問を見つけた後、インターフェイスをクラスに変更しましたが、オブジェクト リテラルを使用してインスタンスを作成することはできません。

タイプ A がどのように消えてしまうのか疑問に思いましたが、生成された JavaScript を見ると問題が説明されています。

var a = {
    member: "foobar"
};
if(a instanceof A) {
    alert(a.member);
}

A はインターフェイスとして表現されないため、実行時の型チェックはできません。

動的言語としての JavaScript にはインターフェイスの概念がないことを理解しています。インターフェイスのタイプチェックを行う方法はありますか?

typescript プレイグラウンドのオートコンプリートは、typescript がメソッドを提供することさえ明らかにしますimplements。どのように使用できますか?

4

23 に答える 23

385

instanceofカスタムタイプガードを記述できるようになったため、キーワードなしで目的を達成できます。

interface A{
    member:string;
}

function instanceOfA(object: any): object is A {
    return 'member' in object;
}

var a:any={member:"foobar"};

if (instanceOfA(a)) {
    alert(a.member);
}

会員数が多い

オブジェクトがタイプに一致するかどうかを判断するために多くのメンバーをチェックする必要がある場合は、代わりに識別子を追加できます。以下は最も基本的な例であり、独自の識別子を管理する必要があります...重複した識別子を避けるために、パターンをより深く理解する必要があります。

interface A{
    discriminator: 'I-AM-A';
    member:string;
}

function instanceOfA(object: any): object is A {
    return object.discriminator === 'I-AM-A';
}

var a:any = {discriminator: 'I-AM-A', member:"foobar"};

if (instanceOfA(a)) {
    alert(a.member);
}
于 2013-01-20T15:57:07.803 に答える
128

TypeScript 1.6 では、ユーザー定義型ガードがその役割を果たします。

interface Foo {
    fooProperty: string;
}

interface Bar {
    barProperty: string;
}

function isFoo(object: any): object is Foo {
    return 'fooProperty' in object;
}

let object: Foo | Bar;

if (isFoo(object)) {
    // `object` has type `Foo`.
    object.fooProperty;
} else {
    // `object` has type `Bar`.
    object.barProperty;
}

Joe Yang が述べたように、TypeScript 2.0 以降では、タグ付き共用体型を利用することさえできます。

interface Foo {
    type: 'foo';
    fooProperty: string;
}

interface Bar {
    type: 'bar';
    barProperty: number;
}

let object: Foo | Bar;

// You will see errors if `strictNullChecks` is enabled.
if (object.type === 'foo') {
    // object has type `Foo`.
    object.fooProperty;
} else {
    // object has type `Bar`.
    object.barProperty;
}

そして、それも一緒に動作しswitchます。

于 2015-11-16T10:35:45.147 に答える
52

ユーザー定義型ガードはどうですか? https://www.typescriptlang.org/docs/handbook/advanced-types.html

interface Bird {
    fly();
    layEggs();
}

interface Fish {
    swim();
    layEggs();
}

function isFish(pet: Fish | Bird): pet is Fish { //magic happens here
    return (<Fish>pet).swim !== undefined;
}

// Both calls to 'swim' and 'fly' are now okay.

if (isFish(pet)) {
    pet.swim();
}
else {
    pet.fly();
}
于 2016-07-16T00:37:48.893 に答える
51

typescript 2.0 でタグ付きユニオンを導入

Typescript 2.0 の機能

interface Square {
    kind: "square";
    size: number;
}

interface Rectangle {
    kind: "rectangle";
    width: number;
    height: number;
}

interface Circle {
    kind: "circle";
    radius: number;
}

type Shape = Square | Rectangle | Circle;

function area(s: Shape) {
    // In the following switch statement, the type of s is narrowed in each case clause
    // according to the value of the discriminant property, thus allowing the other properties
    // of that variant to be accessed without a type assertion.
    switch (s.kind) {
        case "square": return s.size * s.size;
        case "rectangle": return s.width * s.height;
        case "circle": return Math.PI * s.radius * s.radius;
    }
}
于 2016-07-13T09:51:44.260 に答える
12

Typescript の型ガード:

TS には、この目的のための型ガードがあります。彼らは次のように定義しています。

何らかのスコープで型を保証する実行時チェックを実行する式。

これは基本的に、十分な情報がある場合、TS コンパイラが型をより具体的な型に絞り込むことができることを意味します。例えば:

function foo (arg: number | string) {
    if (typeof arg === 'number') {
        // fine, type number has toFixed method
        arg.toFixed()
    } else {
        // Property 'toFixed' does not exist on type 'string'. Did you mean 'fixed'?
        arg.toFixed()
        // TSC can infer that the type is string because 
        // the possibility of type number is eliminated at the if statement
    }
}

質問に戻ると、この型ガードの概念をオブジェクトに適用して、型を判別することもできます。オブジェクトの型ガードを定義するには、戻り値の型が述語型である関数を定義する必要があります。例えば:

interface Dog {
    bark: () => void;
}

// The function isDog is a user defined type guard
// the return type: 'pet is Dog' is a type predicate, 
// it determines whether the object is a Dog
function isDog(pet: object): pet is Dog {
  return (pet as Dog).bark !== undefined;
}

const dog: any = {bark: () => {console.log('woof')}};

if (isDog(dog)) {
    // TS now knows that objects within this if statement are always type Dog
    // This is because the type guard isDog narrowed down the type to Dog
    dog.bark();
}
于 2020-10-31T09:56:09.020 に答える
11

ユーザー定義のガードが使用された上記と同じですが、今回はアロー関数の述語が使用されています

interface A {
  member:string;
}

const check = (p: any): p is A => p.hasOwnProperty('member');

var foo: any = { member: "foobar" };
if (check(foo))
    alert(foo.member);
于 2018-02-21T12:07:31.840 に答える
7

タイプガード

interface MyInterfaced {
    x: number
}

function isMyInterfaced(arg: any): arg is MyInterfaced {
    return arg.x !== undefined;
}

if (isMyInterfaced(obj)) {
    (obj as MyInterfaced ).x;
}
于 2017-06-28T09:54:57.010 に答える
0

これに適切に対処する github パッケージに出くわしたことはわかっていたので、検索履歴を調べた後、ようやく見つけました。typescript-is を確認してください- ttypescript を使用してコードをコンパイルする必要がありますが (私は現在、create-react-app で動作するようにいじめているところです。後で成功/失敗を更新します)、あらゆる種類のことができます。それとクレイジーなものの。ts-validate-typeとは異なり、パッケージも積極的に維持されます。

コンパイラが文句を言うことなく、何かが文字列または数値であるかどうかを確認し、そのように使用できます。

import { is } from 'typescript-is';

const wildString: any = 'a string, but nobody knows at compile time, because it is cast to `any`';

if (is<string>(wildString)) { // returns true
    // wildString can be used as string!
} else {
    // never gets to this branch
}

if (is<number>(wildString)) { // returns false
    // never gets to this branch
} else {
    // Now you know that wildString is not a number!
}

独自のインターフェイスを確認することもできます。

import { is } from 'typescript-is';

interface MyInterface {
    someObject: string;
    without: string;
}

const foreignObject: any = { someObject: 'obtained from the wild', without: 'type safety' };

if (is<MyInterface>(foreignObject)) { // returns true
    const someObject = foreignObject.someObject; // type: string
    const without = foreignObject.without; // type: string
}
于 2021-11-18T01:43:31.593 に答える
0

選択したソリューションと同じ欠点を持つ単純な回避策ですが、このバリアントは JS エラーをキャッチし、オブジェクトのみをパラメーターとして受け入れ、意味のある戻り値を持ちます。

interface A{
    member:string;
}

const implementsA = (o: object): boolean => {
    try {
        return 'member' in o;
    } catch (error) {
        return false;
    }
}

const a:any={member:"foobar"};

implementsA(a) && console.log("a implements A");
// implementsA("str"); // causes TS transpiler error
于 2022-02-24T07:20:09.340 に答える