2017-09-05 19 views
3

タイプガードが存在する場合でも、(最近のバージョンの)TypeScriptがユニオンのタイプを狭めることができないことがあります。 は、この動作ですバグの報告と機能: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' 
} 

質問:どうやらstringkeyof TDataであると想定されているので、

// 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 } 
} 

答えて

1

活字体ハンドブック「はkeyof Tタイプはstringのサブタイプと考えられている。」と言うので、型チェッカーのバグのようです回避策として

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html

、型ガードは、最初のカスタムタイプを除外するために反転させることができます。

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' }); 

あなたはGitHubの中で活字体の問題を検索し、このhasn場合は、新しい問題を提出でき「Tは以前に対処されて:

https://github.com/Microsoft/TypeScript/issues

+0

あなたが正しかった、これは2.6で修正されるバグがあります –

0

typeof name === 'string'keyof TData用型ガードとして機能しません。コンパイラによって2つの異なるタイプがあります。あなたが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'; 
} 
関連する問題