可以在Typescript中改进索引签名吗?

时间:2017-05-06 23:59:52

标签: typescript

我正在使用的一个lib(Aphrodite)有这种类型的定义:

interface StyleDeclaration {
    [key: string]: CSSProperties;
}

我想创建一个子类型,其中key必须是指定列表的子集,但子类型可以用作StyleDeclaration

我最好的尝试是:

type CssTransStyleName =
    'defaultStyle' | 'activeStyle' | 'etcetera'

type CssTransStyleDeclaration = {[K in CssTransStyleName]?: CSSProperties}

这很有效,直到某一点 - 我尝试将实例用作StyleDeclaration。例如,给定:

const cssDeclaration: CssTransStyleDeclaration = {
    style: {
        transformOrigin: 'top left',
    },
}
const ss: StyleDeclaration = cssDeclaration

编译器抱怨说:

Type 'CssTransStyleDeclaration' is not assignable 
 to parameter of type 'StyleDeclaration'.
  Property 'defaultStyle' is incompatible with index signature.
    Type 'CSSProperties | undefined' is not assignable to type 'CSSProperties'.
      Type 'undefined' is not assignable to type 'CSSProperties'.

显然,编译器会解释

{[K in CssTransStyleName]?: CSSProperties}

意思是“CssTransStyleName中的每个属性都具有类型CSSProperties | undefined的值,而我试图说某些属性会出现而有些属性不存在。

投射as StyleDeclaration有效,但我不想使用风管胶带。

我也试过

type CssTransStyleDeclaration = {[K in CssTransStyleName]?: CSSProperties} & StyleDeclaration

但这使它与StyleDeclaration实际上相同;属性不限于CssTransStyleName中的属性。

2 个答案:

答案 0 :(得分:1)

您可以尝试以下操作:

interface CssTransStyle { 
    defaultStyle: any;
    activeStyle: any;
    etcetera: any;
}

type StyleDeclarationOf<T> = {
    [P in keyof T]: CSSProperties;
};

type CssTransStyleDeclaration = StyleDeclarationOf<CssTransStyle> & StyleDeclaration;

以下是一个可以帮助您理解它的示例:

interface CSSProperties {
    someprop: string;
}

interface StyleDeclaration {
    [key: string]: CSSProperties;
}

// This functions only accepts StyleDeclaration
function test(a: StyleDeclaration) {

}

var a: StyleDeclaration = {
    somekey: {
        someprop: "somevalue"
    }
};

test(a); // Works fine because a is StyleDeclaration

interface CssTransStyle { 
    defaultStyle: any;
    activeStyle: any;
    etcetera: any;
}

type StyleDeclarationOf<T> = {
    [P in keyof T]: CSSProperties;
};

type CssTransStyleDeclaration = StyleDeclarationOf<CssTransStyle> & StyleDeclaration;

// Works because b is CssTransStyleDeclaration and StyleDeclaration
var b: CssTransStyleDeclaration = {
    defaultStyle: {
        someprop: "somevalue"
    },
    activeStyle: {
        someprop: "somevalue"
    },
    etcetera: {
        someprop: "somevalue"
    }
};

test(b); // Works fine because is CssTransStyleDeclaration and StyleDeclaration

// ERROR c is StyleDeclaration but not CssTransStyleDeclaration
var c: CssTransStyleDeclaration = {
    somekey: {
        someprop: "somevalue"
    }
};

test(c); // Works fine becase c is StyleDeclaration

答案 1 :(得分:0)

这不是一个答案(对我自己的问题),但如果我可以更改StyleDeclaration,我会将其更改为

type StyleDeclaration<K extends string = string> = {
        [key in K]: CSSProperties;
    }

使一切顺利。 = string是通用的默认值,是TS 2.3中的新功能。