TS2339:联合类型上不存在属性 - 属性字符串 |不明确的
Posted
技术标签:
【中文标题】TS2339:联合类型上不存在属性 - 属性字符串 |不明确的【英文标题】:TS2339: Property does not exist on union type - property string | undefined 【发布时间】:2018-11-23 05:45:01 【问题描述】:我的联合类型有问题,如下所示:
type RepeatForm =
step:
|
repeat: false;
|
repeat: true;
from: undefined;
|
repeat: true;
from: string;
by?: string;
;
;
我有以下函数,我想在其中获取 by
的值(如果存在):
export const getByField = (form: RepeatForm) =>
if (form.step.repeat === false || form.step.from === undefined)
return null;
const x = form.step.from;
return form.step.by;
;
我收到此错误:Property 'by' does not exist on type ' repeat: true; from: undefined; | repeat: true; from: string; by?: string | undefined; '.
Property 'by' does not exist on type ' repeat: true; from: undefined; '.
这让我非常困惑,因为 TypeScript 知道 form.step.from
与 undefined
不同,他甚至将变量类型 x
插入到 string
。
这个问题的原因是什么?那么如何访问by
属性呢?
【问题讨论】:
【参考方案1】:原始PR 用于区分联合非常具体的事实是区分字段必须是string
文字类型(可以选择添加对boolean
和number
文字类型的支持,这似乎有发生)。因此,您根据字段类型(string
与 undefined
)进行区分的用例似乎不受支持。这不起作用,例如:
let u!: v: number, n: number | v: string, s: string
if(typeof u.v === 'number')
u.n // not accesible, type not narrowed
我们可以使用条件类型和自定义类型保护来使事情正常进行:
function isUndefined<T, K extends keyof T>(value : T, field: K) : value is Extract<T, [P in K] : undefined >
return !!value[field]
export const getByField = (form: RepeatForm) =>
if (form.step.repeat === false || isUndefined(form.step, 'from'))
return null;
const x = form.step.from;
return form.step.by;
;
我们还可以创建这个函数的通用版本,允许按任何类型进行缩小:
type ExtractKeysOfType<T, TValue> = [P in keyof T]: T[P] extends TValue ? P : never[keyof T]
function fieldOfType<T, K extends ExtractKeysOfType<T, string>>(value : T, field: K, type: 'string'): value is Extract<T, [P in K] : string >
function fieldOfType<T, K extends ExtractKeysOfType<T, number>>(value : T, field: K, type: 'number'): value is Extract<T, [P in K] : number >
function fieldOfType<T, K extends ExtractKeysOfType<T, boolean>>(value : T, field: K, type: 'boolean'): value is Extract<T, [P in K] : boolean >
function fieldOfType<T, K extends ExtractKeysOfType<T, Function>>(value : T, field: K, type: 'function'): value is Extract<T, [P in K] : Function >
function fieldOfType<T, K extends ExtractKeysOfType<T, symbol>>(value : T, field: K, type: 'symbol'): value is Extract<T, [P in K] : symbol >
function fieldOfType<T, K extends ExtractKeysOfType<T, object>>(value : T, field: K, type: 'object'): value is Extract<T, [P in K] : object >
function fieldOfType<T, K extends ExtractKeysOfType<T, undefined>>(value : T, field: K, type: 'undefined'): value is Extract<T, [P in K] : undefined >
function fieldOfType<T, K extends keyof T, TValue extends T[K]>(value : T, field: K, type: new (...args:any[])=> TValue): value is Extract<T, [P in K] : TValue >
function fieldOfType<T, K extends keyof T>(value : T, field: K, type: string| Function) :boolean
if(typeof type === 'string')
return typeof value[field] === type;
else
return value[field] instanceof type
const getByField = (form: RepeatForm) =>
if (form.step.repeat === false || fieldOfType(form.step, 'from', 'undefined'))
return null;
const x = form.step.from;
return form.step.by;
;
let u: v: number, n: number | v: string, s: string= v: 0, n : 10;
if(fieldOfType(u, 'v', 'number'))
console.log(u.n);
class A private a: undefined;
class B private b: undefined;
let uc: v: A, n: number | v: B, s: string = Math.random() > 0.5 ? v: new B(), s: '10' : v: new A(), n: 10 ;
if(fieldOfType(uc, 'v', A))
console.log(uc.n)
【讨论】:
你知道 TypeScript 是否计划支持它吗? @KonradKlimczak 抱歉,我不知道有什么计划支持这一点,但可能存在问题,这似乎是一个很常见的场景。以上是关于TS2339:联合类型上不存在属性 - 属性字符串 |不明确的的主要内容,如果未能解决你的问题,请参考以下文章
打字稿推断出不正确的类型:TS2339 属性“选定”在类型“字符串”上不存在