繁体   English   中英

检查对象是否正确实现了接口

[英]Check if object correctly implements interface

界面:

export interface User {
  id: number;
  name: string;
  foo: string;
  bar: string;
}

如何检查后端返回的对象是否正确实现了用户界面?

没有通用的方法来做到这一点。 一般的想法是检查对象是否具有预期的属性以及它们是否属于预期的类型。 一般来说,如果服务的输出是已知的,我会挑选一些关键的差异来区分输出的类型并只检查那些。

如果没有更多信息,这种情况的方法是:

function isUser(o: any) : o is User {
    const u: User = o 
    return typeof u.id  === "number"
        && typeof u.name === "string"
        && typeof u.foo === "string"
        && typeof u.bar === "string";
}

let o : any = {};
if(isUser(o)) {
    console.log(o.id); // o is User 
}

检查对象是否与所需类型的示例对象具有所有相同属性的更通用方法是:

function is<T>(o: any, sample:T, strict = true, recursive = true) : o is T {
    if( o == null) return false;
    let s = sample as any;
    // If we have primitives we check that they are of the same type and that type is not object 
    if(typeof s === typeof o && typeof o != "object") return true;

    //If we have an array, then each of the items in the o array must be of the same type as the item in the sample array
    if(o instanceof Array){
        // If the sample was not an arry then we return false;
        if(!(s instanceof Array)) return false;
        let oneSample = s[0];
        let e: any;
        for(e of o) {
            if(!is(e, oneSample, strict, recursive)) return false;
        }
    } else {
        // We check if all the properties of sample are present on o
        for(let key of Object.getOwnPropertyNames(sample)) {
            if(typeof o[key] !== typeof s[key]) return false;
            if(recursive && typeof s[key] == "object" && !is(o[key], s[key], strict, recursive)) return false;
        }
        // We check that o does not have any extra prperties to sample
        if(strict)  {
            for(let key of Object.getOwnPropertyNames(o)) {
                if(s[key] == null) return false;
            }
        }
    }

    return true;
}

用法示例:

// A more complex interface
export interface User {
    id: number;
    name: string;
    foo: string;
    bar: string;
    role: {
        name: string;
        id: number;
    }
    groups: Array<{
        id: number,
        name: string
    }>;
}
// Returned from the service
let o : any = {
    role : { name : "", id: 0 },
    emails: ["a", "b"],
    groups: [ { id: 0, name : ""} ],
    bar: "", foo: "", id: 0, name: "",
};
// What properties will be checked.
const sampleUser: User =  {  
    role : { name : "", id: 0 }, 
    groups: [ { id: 0, name : ""} ],
    emails : [""],
    bar: "", 
    foo: "", 
    id: 0,
    name: "", 
};

if(is(o, sampleUser)){
    console.log(o.id); // o is User 
}

注意我没有以广泛的方式测试通用版本,所以期待一些错误和未处理的极端情况,但是如果你想走这条路,这应该给你一个良好的开端。

接口只存在于 TypeScript 编译时,你不能在运行时使用instanceof东西来检查它。

我认为唯一的方法是编写运行时检查,如下所示:

function implement(obj: any): obj is User {
    return 'id' in obj && typeof obj['id'] === 'number' &&
           'name' in obj && typeof obj['name'] === 'string' &&
           'foo' in obj && typeof obj['foo'] === 'string' &&
           'bar' in obj && typeof obj['bar'] === 'string';
}

implement({
    id: 1,
    name: 3,
    foo: "foo",
    bar: "bar"
});
// returns false

implement({
    name: "name,
    foo: "foo",
    bar: "bar"
});
// returns false

implement({
    id: 1,
    name: "name",
    foo: "foo",
    bar: "bar"
});
// returns true

请注意,这里我假设您使用的是严格的空检查,因此不能将空或未定义分配给您的字段。 对于一般情况,检查的逻辑会更复杂。

下面是一个例子:

getUser(user: User) {
    return user;
}

只要确保你在你的函数中传递了一个 User 类型的用户

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM