Typescript 可以使用字符串文字类型和类型“;“字符串”;是否混合并用作映射类型中的键?

Typescript 可以使用字符串文字类型和类型“;“字符串”;是否混合并用作映射类型中的键?,typescript,types,Typescript,Types,我想定义一个映射类型,其中键'foo'和'bar'的类型为number,所有其他键的类型为string 我的第一个直觉是用这样的条件类型来解决这个问题: type FooOrBar = 'foo' | 'bar'; type MyMappedType = { [key in FooOrBar | string]: key extends FooOrBar ? number : string; } var x: MyMappedType = { foo: 1,

我想定义一个映射类型,其中键
'foo'
'bar'
的类型为
number
,所有其他键的类型为
string

我的第一个直觉是用这样的条件类型来解决这个问题:

type FooOrBar =  'foo' | 'bar';

type MyMappedType = {
        [key in FooOrBar | string]: key extends FooOrBar ? number : string;
}

var x: MyMappedType = {
    foo:  1,   // Type 'number' is not assignable to type 'string'.(2322)
    bar:  2,   // Type 'number' is not assignable to type 'string'.(2322)
    baz: 'I am a string'   // ok!
}

这里的问题是,typescript将typealias
FooOrBar | string
缩小到键中的type
string
。所以事实上typescript将该类型计算为

type MyMappedType = {
        [key in string]: key extends FooOrBar ? number : string;
}

因此,条件
键extends FooOrBar
总是false,类型定义对我的需要是无用的

我的第二个直觉是使用交叉点类型:

type FooOrBar =  'foo' | 'bar';

type MyMappedType = {
        [key in FooOrBar]:number;
} & {
        [key in string]:  string;
};

var x: MyMappedType = { //       Type 'number' is not assignable to type 'string'.(2322)
    foo:  1,
    bar:  2,   
    baz: 'I am a string'  
}

但这也不行


有没有可能在typescript中定义这样的类型?

您可以为每个索引案例创建属性,例如

type numberLiterals = 'foo' | 'bar'

type myMappedType = {
    numbers: { [key in numberLiterals]: number; };
    strings: { [key: string]: string }; 
}

var x: myMappedType = {
    numbers: {
        foo: 1,
        bar: 2,
        // zzz: 5 -> not assignable
    },
    strings: {
        fo: '',
        fooo: ''
        // baar: 1 -> not assignable
    }
}

是的,这会奏效,但这与其说是解决方案,不如说是一种变通办法。我宁愿为我的代码结构定义类型,也不愿将我的代码结构调整为类型。@Simon我认为不可能对字符串执行此操作,因为
[key:string]
已经允许任何字符串(包括联合类型中的字符串)。不过你可以用数字。@Simon事实上,经过一些挖掘,你可以将交叉点改为一个并集,它应该可以按照你的意图工作。出于上述原因,Union仍然不喜欢它。Union将允许初始分配,但您将无法访问“字符串索引”道具(
x['baz']
)@AlekseyL。啊,你说得对,
FooOrBar
属性在访问它们时也会变成一个
string | number
。我想当时我的第一个直觉是对的