Typescript:定义函数,它转换对象,保持键

时间:2015-12-14 12:32:59

标签: typescript

我需要定义一个函数,它接受这种类型的对象:

interface Source<A> {
    [index: string]: A
}

并转换该对象,保留键,但替换值:

interface Target<B> {
    [index: string]: B
}

我也希望为这种情况保持类型检查。这是一个例子:

function transform(source) {
    var result = {}
    Object.keys(source).forEach((key) => {
        result[key] = source[key] + "prefix"
    })
}

var target = transform({
    "key1": 1,
    "key2": 2,
})

// now target has a {"key1": "1prefix", "key2": "2prefix"}

var three = target.key3 // I want to get type error here on compile-time

4 个答案:

答案 0 :(得分:1)

现在可以使用keyof关键字。

type Mock<K, T> = {
    [P in keyof K]: T
}

这将创建一个具有K类型的所有属性的类型,但这些属性的值类型将为T

然后,您可以修改函数以返回Mock<A, B>,编译器会强制执行它。

答案 1 :(得分:0)

我不完全确定你在这之后是什么。你可以这样做:

interface Source<U> {
    [index: string]: U
}

var transform =  <U>(source: Source<U>) : Source<string> => {
    var result: Source<string> = {}
    Object.keys(source).forEach((key) => {
        result[key] = source[key] + "prefix"
    })

    return result;
}

var target = transform({ "key1": 1, "key2": 2 });

// will give error "Type 'string' is not assignable to 'number'"
var blah: number = target["key1"];

// will work (compile and run)..
var blah2: string = target["key1"];

// will compile but crash at run time
var blah2: string = target["random string"];

// will not compile 'Property 'key1' does not  exist on type 'Source<string>'
var blah2: string = target.key1;

最后一个案例永远不会编译。 Typescript在编译时运行所有类型检查。打字稿无法知道存在target['key1']属性。如果这就是你想要的,那就没有办法让它发挥作用。

答案 2 :(得分:0)

一般情况下是不可能的。

TypeScript编译器没有,并且在所有情况下都没有足够的信息来检查您的代码。

答案 3 :(得分:0)

您添加到函数中的类型信息应与其承诺履行的合同相匹配。在原始示例中(此处调整为返回result对象),您可以使用source any类型。

function transform(source) {
    var result = {}

    Object.keys(source).forEach((key) => {
        result[key] = source[key] + "suffix";
    });

    return result;
}

如果您想要进行严格的类型检查,则需要更明确地说明:

interface A {
    key1: number;
    key2: number;
}

interface B {
    key1: string;
    key2: string;
}

function transformAtoB(a: A) : B {
    return <B>transform(a);
}

在上面的示例中,因为您知道输入类型A具有名为key1key2的属性,所以您可以保证返回具有相同属性名称的对象(但不同类型) )。

您可以通过创建一个通用接口来减少接口数量:

interface A<T> {
    key1: T;
    key2: T;
}

function transformAtoB(a: A<number>) : A<string> {
    return <A<string>>transform(a);
}

结果是你有完整的类型信息,这将抓住以下错误:

var target = transformAtoB({
    "key1": 1,
    "key2": 2,
});

console.log(target.key1);
console.log(target.key2);
console.log(target.key3); // Compiler warning