强类型区分解串器

时间:2018-06-13 16:38:04

标签: typescript

我希望得到一些关于是否/如何利用TypeScript来强烈输入类似这样的函数的建议:

function createDeserializer(typeDeserializers) {
    return (data) => {
        const deserializer = typeDeserializers[data.__type];
        return deserializer(data);
    }
}

我希望能够做到这样的事情:

const personDeserializer = createDeserializer({
    'employee': (data) => new Employee(data),
    'customer': (data) => new Customer(data)
});

const person1 = personDeserializer({ __type: 'employee', ... });
const person2 = personDeserializer({ __type: 'customer', ... });

// Here TypeScript knows that person1 is an 'Employee' instance, and person2 is a 'Customer' instance. 

我想我需要在typeDeserializers属性上进行某种键映射,并以某种方式将其映射到返回值,但我有点迷失。

1 个答案:

答案 0 :(得分:3)

你去吧

class Employee {
    constructor(data: any) {
        Object.assign(this, data);
    }
    position: string;
}
class Customer {
    constructor(data: any) {
        Object.assign(this, data);
    }
    clv: number;
}

type DeserializerTypes = { [n in string]: (data: {}) => {} };

function createDeserializer<DS extends DeserializerTypes>(typeDeserializers: DS) {
    return <T extends keyof DS>(data: { __type: T }): ReturnType<DS[T]> => {
        const deserializer = typeDeserializers[data.__type];
        return deserializer(data) as ReturnType<DS[T]>;
    }
}

const personDeserializer = createDeserializer({
    'employee': (data) => new Employee(data),
    'customer': (data) => new Customer(data)
});

const person1 = personDeserializer({ __type: 'employee' }); // inferred as Employee
const person2 = personDeserializer({ __type: 'customer' }); // inferred as Customer

console.log(person1.position);
console.log(1000 + person2.clv);

但如果在反序列化器参数中允许属性,但仍希望TypeScript推断出确切的类型,那会有点棘手:

function createDeserializer<DS extends DeserializerTypes>(typeDeserializers: DS) {
    return <T extends keyof DS, D extends { __type: T }>(data: D): ReturnType<DS[D['__type']]> => {
        const deserializer = typeDeserializers[data.__type];
        return deserializer(data) as ReturnType<DS[T]>;
    }
}

const personDeserializer = createDeserializer({
    'employee': (data) => new Employee(data),
    'customer': (data) => new Customer(data)
});

const person1 = personDeserializer({ __type: 'employee', position: 'a' });
const person2 = personDeserializer({ __type: 'customer', clv: 12 }); 

console.log(person1.position);
console.log(1000 + person2.clv);