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

时间:2018-01-25 12:20:01

标签: typescript

接口:

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

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

3 个答案:

答案 0 :(得分:2)

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

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

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 
}

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

答案 1 :(得分:0)

接口仅在编译时存在于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

请注意,这里我假设您使用严格的空检查,因此无法将null或undefined分配给您的字段。对于一般情况,检查的逻辑将更复杂。

答案 2 :(得分:-1)

以下是一个例子:

getUser(user: User) {
    return user;
}

只需确保在函数中传递User类型的用户