TypeScript条件类型无法识别判别式对象ok状态问题
需求:创建一个对象类型,当status为"ok"时,仅在泛型TData被实例化的情况下存在data键;未实例化TData时,不存在data键。
尝试的代码:
type TStatusObject<TData = never> = | { status: 'idle' } | { status: 'loading' } | { status: 'error'; } | (TData extends never ? { status: 'ok', data?: never } : { status: 'ok'; data: TData }); const fooStatus: TStatusObject = { status: 'ok' };
出现的错误提示:
Type '"ok"' is not assignable to type '"idle" | "loading" | "error"'.ts(2322)
status-object.ts(4, 7): The expected type comes from property 'status' which is declared here on type 'TStatusObject'
错误原因
当你省略泛型参数时,TStatusObject会使用默认的never作为TData的类型,此时进入条件分支{ status: 'ok', data?: never }。
TypeScript中,data?: never表示这个属性要么不存在,要么类型是never——但never是没有任何有效值的类型,这意味着这个分支没有合法的实例可以创建。TypeScript会自动优化掉这个“不可实例化”的联合分支,导致最终的TStatusObject类型只剩下{ status: 'idle' } | { status: 'loading' } | { status: 'error' }三种情况,自然不包含status: 'ok'的可能性,因此抛出类型不匹配的错误。
修复方案
把TData extends never对应的分支改成纯粹的{ status: 'ok' }即可,因为此时我们本来就不需要data键:
type TStatusObject<TData = never> = | { status: 'idle' } | { status: 'loading' } | { status: 'error'; } | (TData extends never ? { status: 'ok' } : { status: 'ok'; data: TData }); // 验证 const fooStatus: TStatusObject = { status: 'ok' }; // 正常通过类型检查 const fooStatusWithData: TStatusObject<string> = { status: 'ok', data: 'success' }; // 带data的情况也正常
内容的提问来源于stack exchange,提问作者Noitidart

