I have a class, and when I initialize it, I pass in a value, or an object about the value
for example
new Field<string>('test')
new Field<string>({value: 'test', inactive: 'preview'})
but state.value
is error. (Property 'value' does not exist on type 'FieldState'. Property 'value' does not exist on type 'T'.ts(2339))
interface BoxedValue<T> {
value: T
inactive: 'disabled'| 'preview'| 'hidden'
}
type FieldState<T> = BoxedValue<T> | T
class Field<T> {
value: T
_pendingValue: T
constructor(state: FieldState<T>) {
if(typeof state === 'object') {
this.value = this._pendingValue = state.value
} else {
this.value = this._pendingValue = state
}
}
}
thank your solution,I amend the code, but I have a new problem Now.
class Field<T> {
value: T
_pendingValue: T
constructor(state: FieldState<T>) {
if(this._isBoxedValue(state)) {
this.value = this._pendingValue = state.value // Property 'value' does not exist on type 'FieldState<T>'.Property 'value' does not exist on type 'T'.
} else {
this.value = this._pendingValue = state
// Type 'FieldState<T>' is not assignable to type 'T'.
// T' could be instantiated with an arbitrary type which could be unrelated to 'FieldState<T>'.
// Type 'BoxedValue<T>' is not assignable to type 'T'.
// 'T' could be instantiated with an arbitrary type which could be unrelated to 'BoxedValue<T>'
}
}
_isBoxedValue(state: FieldState<T>): boolean{
return typeof state === 'object' && state !== null &&
Object.keys(state).length === 2 && 'value' in state && 'inactive' in state;
}
}
Why do I make a mistake when I put the judgment condition in the isboxedvalue function, but not in the constructor?
You should use in operator. Using typeof state ==='object'
can only guarantee that state
is of object
type(if the value of state
is null
, it's a object
type as well), but cannot guarantee that it has a value
property.
The in operator also acts as a narrowing expression for types.
interface BoxedValue<T> {
value: T
inactive: 'disabled'| 'preview'| 'hidden'
}
type FieldState<T> = BoxedValue<T> | T
class Field<T> {
value: T
_pendingValue: T
constructor(state: FieldState<T>) {
if('value' in state) {
this.value = this._pendingValue = state.value
} else {
this.value = this._pendingValue = state
}
}
}
Updated:
You should use User-Defined Type Guards for _isBoxedValue
method. The return type state is BoxedValue<T>
is a type predicate, NOT boolean
.
E.g.
interface BoxedValue<T> {
value: T
inactive: 'disabled'| 'preview'| 'hidden'
}
type FieldState<T> = BoxedValue<T> | T
class Field<T> {
value: T
_pendingValue: T
constructor(state: FieldState<T>) {
if(this._isBoxedValue(state)) {
this.value = this._pendingValue = state.value;
} else {
this.value = this._pendingValue = state;
}
}
_isBoxedValue(state: FieldState<T>): state is BoxedValue<T>{
return typeof state === 'object' && state !== null &&
Object.keys(state).length === 2 && 'value' in state && 'inactive' in state;
}
}
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments