首页 > 解决方案 > 为什么映射类型不能使用通用但有限的键完全解析查找?

问题描述

这是问题的简化:

type Animal = 'dog' | 'cat';

type AnimalSound<T extends Animal> = T extends 'dog'
    ? 'woof'
    : T extends 'cat'
    ? 'meow'
    : never;

const animalSoundMap: {[K in Animal]: AnimalSound<K>} = {
    dog: 'woof',
    cat: 'meow',
};

const lookupSound = <T extends Animal>(animal: T): AnimalSound<T> => {
    const sound = animalSoundMap[animal];
    return sound; 
}

游乐场链接

return行是错误的;错误消息表明该sound变量已解析为'woof' | 'meow',即使TS似乎应该能够根据AnimalSound<T>的类型键入它animalSoundMap。那么为什么类型检查器不喜欢它呢?

标签: typescript

解决方案


为了让 TypeScript 开心,我相信你应该坚持使用@TJ Crowder 的解决方案或者这个:

type Animal = 'dog' | 'cat';

type AnimalSound<T extends Animal> = T extends 'dog'
    ? 'woof'
    : T extends 'cat'
    ? 'meow'
    : never;

const animalSoundMap: { [K in Animal]: AnimalSound<K> } = {
    dog: 'woof',
    cat: 'meow',
};

const lookupSound = <
    AnimalName extends Animal,
    AnimalMap extends { [Name in AnimalName]: AnimalSound<Name> }
>(animalMap: AnimalMap, animal: AnimalName):
    AnimalMap[AnimalName] =>
    animalMap[animal]

如果要推断返回类型,还应该推断并制作函数参数的一部分animalMap操场

您甚至不需要定义显式返回类型,TS 能够从函数体中推断出它:

const lookupSound = <T extends Animal>(animal: T)=> {
    const sound = animalSoundMap[animal];

    return sound;
}

const result = lookupSound('cat') // "meow"

条件类型不能以您期望的方式在返回类型的地方工作。如果您在函数重载中使用条件类型,它可能会起作用:

function lookupSound<T extends Animal>(animal: T): AnimalSound<T>
function lookupSound<T extends Animal>(animal: T) {
    const sound = animalSoundMap[animal];
    return sound;
}



推荐阅读