การตรวจสอบประเภทอินเตอร์เฟสด้วย Typescript


294

คำถามนี้เป็นแบบแอนะล็อกโดยตรงกับการตรวจสอบประเภท Class ด้วย TypeScript

ฉันจำเป็นต้องค้นหารันไทม์หากตัวแปรชนิดใดที่ใช้อินเทอร์เฟซ นี่คือรหัสของฉัน:

interface A{
    member:string;
}

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

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

หากคุณป้อนรหัสนี้ในสนามเด็กเล่น typescript บรรทัดสุดท้ายจะถูกทำเครื่องหมายว่าเป็นข้อผิดพลาด "ชื่อ A ไม่มีอยู่ในขอบเขตปัจจุบัน" แต่นั่นไม่เป็นความจริงชื่อนี้มีอยู่ในขอบเขตปัจจุบัน ฉันสามารถเปลี่ยนการประกาศตัวแปรเป็นvar a:A={member:"foobar"};โดยไม่มีการร้องเรียนจากบรรณาธิการ หลังจากท่องเว็บและค้นหาคำถามอื่น ๆ บนดังนั้นฉันเปลี่ยนอินเทอร์เฟซเป็นคลาส แต่จากนั้นฉันไม่สามารถใช้ตัวอักษรวัตถุเพื่อสร้างอินสแตนซ์

ฉันสงสัยว่าประเภท A จะหายไปเช่นนั้นได้อย่างไรเมื่อดูที่จาวาสคริปต์ที่สร้างขึ้นจะอธิบายถึงปัญหา:

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

ไม่มีการแทนค่า A ในฐานะอินเตอร์เฟสดังนั้นจึงไม่สามารถตรวจสอบชนิดรันไทม์ได้

ฉันเข้าใจว่าจาวาสคริปต์เป็นภาษาแบบไดนามิกไม่มีแนวคิดของส่วนต่อประสาน มีวิธีใดบ้างที่จะพิมพ์การตรวจสอบอินเทอร์เฟซ?

การเติมเต็มอัตโนมัติ typescript สนามเด็กเล่นเผย typescript implementsว่ายังมีวิธีการ ฉันจะใช้มันได้อย่างไร


4
JavaScript ไม่มีแนวคิดของอินเตอร์เฟส แต่นั่นไม่ใช่เพราะเป็นภาษาแบบไดนามิก เป็นเพราะอินเตอร์เฟสยังไม่ได้ใช้งาน
trusktr

ใช่ แต่คุณสามารถใช้คลาสแทนอินเตอร์เฟสได้ ดูนี้ตัวอย่างเช่น
Alexey Baranoshnikov

เห็นได้ชัดว่าไม่ใช่ในปี 2560 คำถามที่เกี่ยวข้องสุด ๆ ตอนนี้
doublejosh

คำตอบ:


221

คุณสามารถบรรลุสิ่งที่คุณต้องการโดยไม่ต้อง 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);
}

สมาชิกจำนวนมาก

หากคุณต้องการตรวจสอบสมาชิกจำนวนมากเพื่อตรวจสอบว่าวัตถุที่ตรงกับประเภทของคุณคุณสามารถเพิ่ม discriminator ด้านล่างเป็นตัวอย่างพื้นฐานที่สุดและต้องการให้คุณจัดการกับผู้เลือกปฏิบัติของคุณ ... คุณจะต้องเจาะลึกลงไปในรูปแบบเพื่อให้แน่ใจว่าคุณหลีกเลี่ยงการเลือกปฏิบัติซ้ำซ้อน

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);
}

85
"ไม่สามารถตรวจสอบอินเทอร์เฟซได้" มีพวกเขาเพิ่งยังไม่ได้ใช้มันด้วยเหตุผลใดก็ตาม
trusktr

16
และถ้าอินเทอร์เฟซมีสมาชิก 100 คนคุณต้องตรวจสอบทั้งหมด 100 ครั้งหรือไม่ foobar
Jenny O'Reilly

4
คุณสามารถเพิ่ม discriminator ไปยังวัตถุคุณมากกว่าที่ตรวจสอบทั้งหมด 100 ...
เฟนตัน

7
กระบวนทัศน์ของ discriminator นี้ (ดังที่เขียนไว้ที่นี่) ไม่รองรับส่วนต่อประสานที่ขยายเพิ่มเติม อินเตอร์เฟสที่ได้รับจะคืนค่า false ถ้าตรวจสอบว่าเป็นอินสแตนซ์ของอินเทอร์เฟซพื้นฐานหรือไม่
แอรอน

1
@ เฟนตันบางทีฉันไม่รู้เรื่องนี้มากพอ แต่สมมติว่าคุณมีอินเตอร์เฟส B ที่ขยายอินเตอร์เฟส A คุณต้องการisInstanceOfA(instantiatedB)กลับจริง แต่คุณต้องการisInstanceOfB(instantiatedA)คืนเท็จ เพื่อที่จะเกิดขึ้นในภายหลังผู้วินิจฉัยของ B จะไม่ต้องเป็น 'I-AM-A' หรือไม่?
แอรอน

87

ใน 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;
}

และดังที่โจวหยางกล่าวถึง: ตั้งแต่ 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เช่นกัน


1
มันดูค่อนข้างอยากรู้อยากเห็น เห็นได้ชัดว่ามีข้อมูลเมตาบางประเภท ทำไมต้องเปิดเผยด้วยไวยากรณ์ตัวป้องกันประเภทนี้ เนื่องจากข้อ จำกัด "วัตถุคืออินเทอร์เฟซ" ซึ่งอยู่ถัดจากฟังก์ชันใช้งานซึ่งตรงข้ามกับ isinstanceof แม่นยำยิ่งขึ้นคุณสามารถใช้ "object is interface" ใน if statement ได้โดยตรงหรือไม่? แต่ในกรณีใด ๆ ไวยากรณ์ที่น่าสนใจมาก +1 จากฉัน
lhk

1
@ lhk ไม่มีคำสั่งเช่นนั้นมันก็เหมือนประเภทพิเศษที่บอกว่าควรจะพิมพ์ประเภทให้แคบลงในสาขาที่มีเงื่อนไข เนื่องจาก "ขอบเขต" ของ TypeScript ฉันเชื่อว่าจะไม่มีคำสั่งดังกล่าวแม้แต่ในอนาคต ความแตกต่างระหว่างobject is typeและobject instanceof classคือพิมพ์ใน TypeScript เป็นโครงสร้างมันสนใจเฉพาะ "รูปร่าง" แทนที่จะเป็นวัตถุที่ได้รับรูปร่างจาก: วัตถุธรรมดาหรือตัวอย่างของชั้นเรียนมันไม่สำคัญ
vilicvane

2
เพื่อล้างความเข้าใจผิดที่คำตอบนี้สามารถสร้างได้: ไม่มีข้อมูลเมตาที่จะหักประเภทของวัตถุหรือส่วนต่อประสานระหว่างรันไทม์
Mostruash

@mostruash Yep ครึ่งหลังของคำตอบจะไม่สามารถใช้งานได้แม้จะคอมไพล์แล้วก็ตาม
trusktr

4
โอ้ แต่สิ่งนี้จะต้องสมมติว่าเมื่อรันไทม์ออบเจ็กต์เหล่านี้จะถูกสร้างขึ้นด้วยtypeคุณสมบัติ ในกรณีที่มันใช้งานได้ ตัวอย่างนั้นไม่แสดงข้อเท็จจริงนี้
trusktr

40

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

ฉันกำลังใช้รุ่นเบต้า 2.0 แต่สหภาพที่ติดแท็กไม่ทำงาน <TypeScriptToolsVersion> 2.0 </TypeScriptToolsVersion>
Makla

คอมไพล์ด้วยบิลด์บิลด์ตอนกลางคืน แต่ Intellisense ไม่ทำงาน นอกจากนี้ยังแสดงรายการข้อผิดพลาด: ความกว้าง / ขนาด / ... คุณสมบัติไม่มีอยู่ในประเภท 'สแควร์ | สี่เหลี่ยมผืนผ้า | วงกลมในคำสั่งกรณี แต่มันก็รวบรวม
Makla

23
นี่เป็นเพียงการใช้เครื่องมือจำแนก
Erik Philips

33

ชนิดยามที่ผู้ใช้กำหนดเองเป็นอย่างไร 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();
}

3
นี่คือคำตอบที่ฉันโปรดปราน - คล้ายกับstackoverflow.com/a/33733258/469777แต่ไม่มีสายเวทที่อาจแตกเนื่องจากสิ่งต่าง ๆ เช่นการทำให้เป็น minification
Stafford Williams

1
สิ่งนี้ไม่ได้ผลสำหรับฉันด้วยเหตุผลบางอย่าง แต่(pet as Fish).swim !== undefined;ทำ
CyberMew

18

ตอนนี้เป็นไปได้ฉันเพิ่งเปิดตัวTypeScriptคอมไพเลอร์รุ่นปรับปรุงที่ให้ความสามารถในการสะท้อนเต็ม คุณสามารถสร้างอินสแตนซ์ของคลาสจากออบเจ็กต์เมทาดาทาดึงเมทาดาทาจากตัวสร้างคลาสและตรวจสอบอินเทอร์เฟซ / คลาสที่รันไทม์ คุณสามารถตรวจสอบได้ที่นี่

ตัวอย่างการใช้งาน:

ในหนึ่งในไฟล์ typescript ของคุณสร้างอินเทอร์เฟซและคลาสที่ใช้งานดังต่อไปนี้:

interface MyInterface {
    doSomething(what: string): number;
}

class MyClass implements MyInterface {
    counter = 0;

    doSomething(what: string): number {
        console.log('Doing ' + what);
        return this.counter++;
    }
}

ตอนนี้ลองพิมพ์รายการอินเตอร์เฟสที่ใช้งานแล้ว

for (let classInterface of MyClass.getClass().implements) {
    console.log('Implemented interface: ' + classInterface.name)
}

รวบรวมกับ reflec-ts และเปิดมัน:

$ node main.js
Implemented interface: MyInterface
Member name: counter - member kind: number
Member name: doSomething - member kind: function

ดู reflection.d.ts สำหรับInterfaceรายละเอียดประเภทเมตา

UPDATE: คุณสามารถหาตัวอย่างการทำงานได้ที่นี่


8
downvoted เพราะฉันคิดว่านี่โง่ แต่หยุดชั่วคราวสักครู่ดูที่หน้า GitHub ของคุณและเห็นว่ามันถูกปรับปรุงและบันทึกเป็นอย่างดีดังนั้น upvoted แทน :-) ตอนนี้ฉันยังไม่สามารถใช้มันเองได้implementsแต่ต้องการยอมรับข้อผูกพันของคุณและไม่ต้องการเป็นค่าเฉลี่ย :-)
Simon_Weaver

5
ที่จริงแล้ววัตถุประสงค์หลักที่ฉันเห็นในคุณสมบัติการสะท้อนนี้คือการสร้างกรอบ IoC ที่ดีขึ้นเหมือนในโลก Java ที่มีมานานแล้ว (Spring เป็นตัวแรกและสำคัญที่สุด) ฉันเชื่อมั่นว่า TypeScript สามารถเป็นหนึ่งในเครื่องมือการพัฒนาที่ดีที่สุดในอนาคตและการสะท้อนกลับเป็นหนึ่งในคุณสมบัติที่ต้องการจริงๆ
pcan

5
... เอ่ออะไรเราต้องม้วนคอมไพเลอร์ "การปรับปรุง" เหล่านี้ในการสร้าง typescript ในอนาคตหรือไม่ นี่คือส้อมของ typescript อย่างมีประสิทธิภาพไม่ใช่ typescript ของตัวเองใช่ไหม ถ้าใช่นี่ไม่ใช่วิธีแก้ปัญหาระยะยาวที่เป็นไปได้
dudewad

1
@dudewad ดังที่กล่าวไว้ในหัวข้ออื่น ๆ อีกมากมายนี่เป็นวิธีแก้ปัญหาชั่วคราว เรากำลังรอความสามารถในการรวบรวมคอมไพเลอร์ผ่านหม้อแปลง โปรดดูปัญหาที่เกี่ยวข้องใน repo TypeScript อย่างเป็นทางการ ยิ่งกว่านั้นภาษาที่พิมพ์ตัวหนาทั้งหมดที่นำมาใช้อย่างกว้างขวางมีภาพสะท้อนและฉันคิดว่า TypeScript ควรมีเช่นกัน เช่นเดียวกับฉันผู้ใช้หลายคนคิดเช่นนั้น
pcan

ใช่ไม่ใช่ว่าฉันไม่เห็นด้วย - ฉันต้องการสิ่งนี้ด้วย เพียงแค่หมุนคอมไพเลอร์ที่กำหนดเอง ... นั่นไม่ได้หมายความว่าแพตช์ถัดไปของ typescript จะต้องได้รับการย้าย? หากคุณกำลังบำรุงรักษามันก็ต้องชื่นชม ดูเหมือนว่าจะทำงานมาก ไม่เคาะมัน
dudewad


8

นี่เป็นอีกตัวเลือกหนึ่ง: โมดูลts-interface-builderจัดเตรียมเครื่องมือ build-time ที่แปลงอินเทอร์เฟซ TypeScript ให้เป็น runtime descriptor และts-interface-checkerสามารถตรวจสอบว่าวัตถุเป็นไปตามที่กำหนดหรือไม่

สำหรับตัวอย่างของ OP

interface A {
  member: string;
}

ก่อนอื่นคุณจะเรียกใช้ts-interface-builderไฟล์ที่สร้างไฟล์ย่อใหม่พร้อม descriptor foo-ti.tsซึ่งคุณสามารถใช้ดังนี้

import fooDesc from './foo-ti.ts';
import {createCheckers} from "ts-interface-checker";
const {A} = createCheckers(fooDesc);

A.check({member: "hello"});           // OK
A.check({member: 17});                // Fails with ".member is not a string" 

คุณสามารถสร้างฟังก์ชั่นป้องกันชนิดหนึ่ง:

function isA(value: any): value is A { return A.test(value); }

6

ฉันอยากจะชี้ให้เห็นว่า TypeScript ไม่ได้มีกลไกโดยตรงสำหรับการทดสอบแบบไดนามิกว่าวัตถุที่ใช้อินเตอร์เฟซที่เฉพาะเจาะจง

แต่รหัส TypeScript สามารถใช้เทคนิค JavaScript ในการตรวจสอบว่ามีชุดสมาชิกที่เหมาะสมบนวัตถุหรือไม่ ตัวอย่างเช่น:

var obj : any = new Foo();

if (obj.someInterfaceMethod) {
    ...
}

4
ถ้าคุณมีรูปร่างที่ซับซ้อนล่ะ คุณไม่ต้องการ hardcode ทุก ๆ ทรัพย์สินที่ระดับความลึก
Tom

@Tom ฉันเดาว่าคุณสามารถผ่าน (เป็นพารามิเตอร์ตัวที่สองไปยังฟังก์ชั่นตรวจสอบ) ค่าเวลาทำงานหรือตัวอย่าง / ตัวอย่าง - เช่นวัตถุของอินเตอร์เฟซที่คุณต้องการ จากนั้นแทนที่จะเป็นรหัสฮาร์ดโค้ดคุณเขียนตัวอย่างของอินเทอร์เฟซที่คุณต้องการ ... และเขียนโค้ดเปรียบเทียบออบเจ็กต์แบบครั้งเดียว (โดยใช้เช่นfor (element in obj) {} ) เพื่อตรวจสอบว่าวัตถุทั้งสองมีองค์ประกอบที่คล้ายกันประเภทเดียวกัน
ChrisW

5

TypeGuards

interface MyInterfaced {
    x: number
}

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

if (isMyInterfaced(obj)) {
    (obj as MyInterfaced ).x;
}

2
"arg is MyInterfaced" เป็นคำอธิบายประกอบที่น่าสนใจ จะเกิดอะไรขึ้นถ้าสิ่งนั้นล้มเหลว? ดูเหมือนว่าการรวบรวมอินเทอร์เฟซเวลาตรวจสอบ - ซึ่งจะเป็นสิ่งที่ฉันต้องการในครั้งแรก แต่ถ้าคอมไพเลอร์ตรวจสอบพารามิเตอร์ทำไมมีฟังก์ชั่นร่างกายเลย และหากการตรวจสอบดังกล่าวเป็นไปได้ให้ย้ายไปยังฟังก์ชันที่แยกต่างหาก
lhk

1
@lhk เพียงอ่านเอกสารตัวพิมพ์เกี่ยวกับตัวพิมพ์ ... typescriptlang.org/docs/handbook/advanced-types.html
Dmitry Matveev

3

จากคำตอบของเฟนตันต่อไปนี้คือการใช้ฟังก์ชั่นของฉันในการตรวจสอบว่าobjectมีปุ่มที่interfaceมีทั้งแบบเต็มหรือบางส่วน

ขึ้นอยู่กับกรณีการใช้งานของคุณคุณอาจต้องตรวจสอบประเภทของคุณสมบัติของแต่ละอินเตอร์เฟส รหัสด้านล่างไม่ได้ทำเช่นนั้น

function implementsTKeys<T>(obj: any, keys: (keyof T)[]): obj is T {
    if (!obj || !Array.isArray(keys)) {
        return false;
    }

    const implementKeys = keys.reduce((impl, key) => impl && key in obj, true);

    return implementKeys;
}

ตัวอย่างการใช้งาน:

interface A {
    propOfA: string;
    methodOfA: Function;
}

let objectA: any = { propOfA: '' };

// Check if objectA partially implements A
let implementsA = implementsTKeys<A>(objectA, ['propOfA']);

console.log(implementsA); // true

objectA.methodOfA = () => true;

// Check if objectA fully implements A
implementsA = implementsTKeys<A>(objectA, ['propOfA', 'methodOfA']);

console.log(implementsA); // true

objectA = {};

// Check again if objectA fully implements A
implementsA = implementsTKeys<A>(objectA, ['propOfA', 'methodOfA']);

console.log(implementsA); // false, as objectA now is an empty object

2
export interface ConfSteps {
    group: string;
    key: string;
    steps: string[];
}
private verify(): void {
    const obj = `{
      "group": "group",
      "key": "key",
      "steps": [],
      "stepsPlus": []
    } `;
    if (this.implementsObject<ConfSteps>(obj, ['group', 'key', 'steps'])) {
      console.log(`Implements ConfSteps: ${obj}`);
    }
  }
private objProperties: Array<string> = [];

private implementsObject<T>(obj: any, keys: (keyof T)[]): boolean {
    JSON.parse(JSON.stringify(obj), (key, value) => {
      this.objProperties.push(key);
    });
    for (const key of keys) {
      if (!this.objProperties.includes(key.toString())) {
        return false;
      }
    }
    this.objProperties = null;
    return true;
  }

1
ในขณะที่รหัสนี้อาจตอบคำถาม แต่มีบริบทเพิ่มเติมเกี่ยวกับสาเหตุและ / หรือวิธีการที่รหัสนี้ตอบคำถามช่วยปรับปรุงมูลค่าระยะยาว
xiawi

0

เนื่องจากไม่ทราบชนิดของรันไทม์ฉันจึงเขียนโค้ดดังนี้เพื่อเปรียบเทียบออบเจ็กต์ที่ไม่รู้จักไม่ใช่กับประเภท แต่เปรียบเทียบกับออบเจ็กต์ประเภทที่ทราบ:

  1. สร้างวัตถุตัวอย่างของประเภทที่เหมาะสม
  2. ระบุองค์ประกอบที่เป็นตัวเลือก
  3. ทำการเปรียบเทียบวัตถุที่ไม่รู้จักของคุณกับวัตถุตัวอย่างนี้อย่างละเอียด

นี่คือโค้ด (อินเตอร์เฟสที่ไม่เชื่อเรื่องพระเจ้า) ที่ฉันใช้สำหรับการเปรียบเทียบแบบลึก:

function assertTypeT<T>(loaded: any, wanted: T, optional?: Set<string>): T {
  // this is called recursively to compare each element
  function assertType(found: any, wanted: any, keyNames?: string): void {
    if (typeof wanted !== typeof found) {
      throw new Error(`assertType expected ${typeof wanted} but found ${typeof found}`);
    }
    switch (typeof wanted) {
      case "boolean":
      case "number":
      case "string":
        return; // primitive value type -- done checking
      case "object":
        break; // more to check
      case "undefined":
      case "symbol":
      case "function":
      default:
        throw new Error(`assertType does not support ${typeof wanted}`);
    }
    if (Array.isArray(wanted)) {
      if (!Array.isArray(found)) {
        throw new Error(`assertType expected an array but found ${found}`);
      }
      if (wanted.length === 1) {
        // assume we want a homogenous array with all elements the same type
        for (const element of found) {
          assertType(element, wanted[0]);
        }
      } else {
        // assume we want a tuple
        if (found.length !== wanted.length) {
          throw new Error(
            `assertType expected tuple length ${wanted.length} found ${found.length}`);
        }
        for (let i = 0; i < wanted.length; ++i) {
          assertType(found[i], wanted[i]);
        }
      }
      return;
    }
    for (const key in wanted) {
      const expectedKey = keyNames ? keyNames + "." + key : key;
      if (typeof found[key] === 'undefined') {
        if (!optional || !optional.has(expectedKey)) {
          throw new Error(`assertType expected key ${expectedKey}`);
        }
      } else {
        assertType(found[key], wanted[key], expectedKey);
      }
    }
  }

  assertType(loaded, wanted);
  return loaded as T;
}

ด้านล่างเป็นตัวอย่างของวิธีการใช้งาน

ในตัวอย่างนี้ฉันคาดว่า JSON จะมีอาร์เรย์ของ tuples ซึ่งองค์ประกอบที่สองเป็นตัวอย่างของอินเทอร์เฟซที่เรียกว่าUser(ซึ่งมีองค์ประกอบที่เป็นตัวเลือกสองรายการ)

การตรวจสอบชนิดของ TypeScript จะทำให้แน่ใจว่าวัตถุตัวอย่างของฉันถูกต้องจากนั้นฟังก์ชัน assertTypeT จะตรวจสอบว่าวัตถุที่ไม่รู้จัก (โหลดจาก JSON) ตรงกับวัตถุตัวอย่าง

export function loadUsers(): Map<number, User> {
  const found = require("./users.json");
  const sample: [number, User] = [
    49942,
    {
      "name": "ChrisW",
      "email": "example@example.com",
      "gravatarHash": "75bfdecf63c3495489123fe9c0b833e1",
      "profile": {
        "location": "Normandy",
        "aboutMe": "I wrote this!\n\nFurther details are to be supplied ..."
      },
      "favourites": []
    }
  ];
  const optional: Set<string> = new Set<string>(["profile.aboutMe", "profile.location"]);
  const loaded: [number, User][] = assertTypeT(found, [sample], optional);
  return new Map<number, User>(loaded);
}

คุณสามารถเรียกใช้เช็คเช่นนี้ในการใช้งานของยามชนิดที่ผู้ใช้กำหนด


0

คุณสามารถตรวจสอบประเภท TypeScript ที่รันไทม์โดยใช้ts-validate-typeเช่นนั้น (ไม่ต้องการปลั๊กอิน Babel):

const user = validateType<{ name: string }>(data);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.