有没有办法在TypeScript中定义一个setter函数?

时间:2015-01-18 15:33:18

标签: typescript

我发现以下getter函数非常有用且可重用,因为它可以获得具有此类属性的任何对象的属性key的值。

export function keyOf<a>(value: { key: a; }) : a {
   return value.key;
}

同样,我可以定义一个通用的setter函数:

export function withKey<a>(value: { key: a; }, key: a) : void {
    value.key = key;
}

唯一的问题是,我需要使用修改后的void属性返回原始对象value,而不是返回key。像这样:

export function withKey<b, a extends { key: b }>(value: a, key: b) : a {
   value.key = key;
   return value;
}

但这不是一个有效的TypeScript代码。

问题:我怎样才能获得一个类型安全的通用setter函数,它返回原始对象及其属性集?

更新:

在当前TypeScript中,类型参数之间的依赖关系是被禁止的。我相信它是为了使类型系统更简单,更快速。但是,此限制会阻止某些有用的场景,例如相关场景。有一个hack可以将类型参数之间的依赖关系转换为函数依赖关系:

export function withKey<a, b>(
    value: a,
    key: b,
    toAssignable: (value: a) => { key: b } = function<c>(anything: c) : c {
        return anything;
    }
) : a {
    toAssignable(value).key = key;
    return value;
}

这看起来很丑陋并且改变了原始签名,但它编译并且有效。

有没有人知道更好的方法?

1 个答案:

答案 0 :(得分:0)

我玩了一下,我只想出这个:

// === unsave approach ===  

/**
 * Test class
 */ 
class MyClassWithoutKey {
    public youCanCallThis() { }
}

/**
 * The setter function
 */
function withKeyUnsafe<T>(value: T, key: any) {
    (<any>value).key = key;
    return value;
}

// compile test
var w = withKeyUnsafe(new MyClassWithoutKey(), 2).youCanCallThis();

和此:

// === typesave approach ===

/**
 * Test class
 */     
class MyClassWithKey {
    key: string;
    public youCanCallThis() { }
}

/**
 * Helper interface
 */ 
interface WithKey<T> {
    key: T;
}

/**
 * Factory function that adds type constraint
 */
function withKeyTypeSave<T>() {
    /**
     * The actual setter function
     */
    return function <WithKeyT extends WithKey<T>>(value: WithKeyT, key: T) {
        value.key = key;
        return value;
    }
}


// compile test -- works
withKeyTypeSave<string>()(new MyClassWithKey(), "new key").youCanCallThis();

// compile test -- fails
withKeyTypeSave<number>()(new MyClassWithKey(), "new key").youCanCallThis();

// compile test -- fails
withKeyTypeSave<string>()(new MyClassWithKey(), 3).youCanCallThis();