Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jquery-ui/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Typescript 类型脚本联合类型推断失败_Typescript - Fatal编程技术网

Typescript 类型脚本联合类型推断失败

Typescript 类型脚本联合类型推断失败,typescript,Typescript,有时,即使存在类型保护,TypeScript(最新版本)似乎也无法缩小联合类型。 此行为是错误还是功能: 序言: // some config interface Config { name: string; option1?: number; option2?: boolean; } // arbitrary type interface Entity { a: number; b: number; } // name aware type guar

有时,即使存在类型保护,TypeScript(最新版本)似乎也无法缩小联合类型。 此行为是错误还是功能:

序言:

// some config
interface Config {
    name: string;
    option1?: number;
    option2?: boolean;
}

// arbitrary type
interface Entity {
    a: number;
    b: number;
}

// name aware type guard for entity property-to-config map
// some default config may be replaced with a property name
type TConfigSet<TData> = {
    [P in keyof TData]: (Config & { name: P }) | P;
}

// example of TConfigSet usage
const EntityConfigs: TConfigSet<Entity> = {
    a: {
        name: 'a',
        option2: true
    },
    b: 'b'
}
//一些配置
接口配置{
名称:字符串;
选项1:编号;
选项2:布尔值;
}
//任意类型
接口实体{
a:数字;
b:数字;
}
//实体属性到配置映射的名称感知类型保护
//某些默认配置可能会替换为属性名称
类型TConfigSet={
[P in keyof TData]:(Config&{name:P})P;
}
//TConfigSet使用示例
const EntityConfigs:TConfigSet={
a:{
名称:‘a’,
选项2:正确
},
b:‘b’
}
问题:

// this function compiles
function TypeLooseFieldToName(name: string | Config): string {
    if (typeof name === 'string') return name;
    else return name.name;
}

// this one doesn't
function TypeStrictFieldToName<TData>(name: keyof TData | { name: keyof TData }): keyof TData {
    if (typeof name === 'string') return name;
    else return name.name; // still keyof TData | { name: keyof TData }, should be shrinked to { name: keyof TData }
}
//此函数编译
函数类型LooseFieldTonName(名称:string | Config):string{
if(typeof name==='string')返回名称;
否则返回name.name;
}
//这个没有
函数类型StrictFieldToName(名称:keyof-TData |{name:keyof-TData}):keyof-TData{
if(typeof name==='string')返回名称;
else返回name.name;//still keyof TData |{name:keyof TData},应收缩为{name:keyof TData}
}

typeof name===“string”
不能作为
keyof-TData
的类型保护,因为编译器显然假定
string
keyof-TData
是两种不同的类型。如果您为
keyof-TData
添加自己的自定义类型保护,它将起作用:

function TypeStrictFieldToName<TData>(name: keyof TData | { name: keyof TData }): keyof TData {
    if (isKeyofTData<TData>(name)) return name;
    else return name.name; // type of name here is { name: keyof TData }
}

function isKeyofTData<TData>(name: keyof TData | {}): name is keyof TData {
    return typeof name === 'string';
}
函数类型strictfieldtoname(名称:keyof-TData}{name:keyof-TData}):keyof-TData{
if(isKeyofTData(name))返回名称;
else返回name.name;//此处的名称类型为{name:keyof-TData}
}
函数isKeyofTData(名称:keyof-TData |{}):名称为keyof-TData{
返回typeof name==='string';
}

这似乎是类型检查器中的一个错误,因为TypeScript手册中说“一个
keyof T
类型被认为是
字符串的一个子类型。”

作为一种解决方法,可以反转类型保护以首先排除自定义类型:

function hasName(obj: string | { name: string }): obj is { name: string } {
    return typeof obj.name === 'string';
}

function getName<TData>(name: keyof TData | { name: keyof TData }): keyof TData {
    if (hasName(name)) return name.name;
    else return name;
}

// compiles with valid keys
getName<Entity>('a');
getName<Entity>({ name: 'a' });

// doesn't compile with invalid keys
getName<Entity>('z');
getName<Entity>({ name: 'z' });
函数hasName(obj:string |{name:string}):obj是{name:string}{
返回objectj.name的类型=='string';
}
函数getName(名称:keyof-TData |{name:keyof-TData}):keyof-TData{
if(hasName(name))返回name.name;
否则返回名称;
}
//使用有效键进行编译
getName('a');
getName({name:'a'});
//不使用无效键编译
getName('z');
getName({name:'z'});
您可以在GitHub中搜索TypeScript问题,并在以前未解决的情况下提交新问题: