如何为联合类型参数提供默认值而无需获取“可以用其他约束子类型实例化”

时间:2019-10-28 20:19:20

标签: typescript typescript-generics

作为my previous question ...的后续行动...

在以下示例中,是否可以为valueProp提供默认值?

type ValueType = 'value' | 'defaultValue'

type Props<T extends ValueType> =
  Record<T, string> 
  & { other: string }

function props<T extends ValueType>(valueProp: T): Props<T> {
  return {
    [valueProp]: 'value',
    other: 'other',
  } as Props<T>
}

let { defaultValue, other } = props('defaultValue') // ok
let { value } = props('value') // ok

Play


当我尝试这样做时:

function props<T extends ValueType>(valueProp: T = 'value'): Props<T> {
  return {
    [valueProp]: 'value',
    other: 'other',
  } as Props<T>
}

,出现此错误:

Type '"value"' is not assignable to type 'T'.
  '"value"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'ValueType'.

我一般都会理解此错误(1234),但仍然不总是知道解决的最佳方法此错误。

有没有一种简单的方法可以做我想做的事情?

似乎应该有一种简单的方法来提供默认值,但是也许默认值与通用类型约束混合得不好?

通用类型的默认类型?

我尝试过:

function props<T extends ValueType = 'value'>(valueProp: T = 'value'): Props<T> {
  return {
    [valueProp]: 'value',
    other: 'other',
  } as Props<T>
}

当然会出现相同的错误,因为如果提供了特定的defaultValue,T仍然可能是T

props<'defaultValue'>()

类型断言?

我考虑过这样做,可以编译,但是仍然不能阻止valueProp与T意见分歧:

function props<T extends ValueType>(valueProp: T = 'value' as T): Props<T> {
  return {
    [valueProp]: 'value',
    other: 'other',
  } as Props<T>
}

console.log(props<'defaultValue'>())
// => {value: "value", other: "other"}

有些复杂吗?

我仍然希望有一个简单的解决方案,但是如果没有,也许更复杂的方法会起作用?

也许使用的映射表可以将类型映射到该类型的默认

对于灵感,也许有点像:

1 个答案:

答案 0 :(得分:0)

基于Titian Cernicova-Dragomir的评论,我们可以使用函数重载非常简单地做到这一点:

type ValueType = 'value' | 'defaultValue'

type Props<T extends ValueType> =
  Record<T, string> 
  & { other: string }

function props<T extends ValueType>(valueProp: T): Props<T>
function props(): Props<'value'>
function props(valueProp: ValueType | undefined = 'value') {
  return {
    [valueProp]: 'value',
    other: 'other',
  }
}

Play


或者如果我们要将valueProp从位置参数移动到伪命名参数(使用对象分解):

type PropsOptions<VT extends ValueType | undefined> = {
  valueProp?: VT
}

function props<VT extends ValueType>({valueProp}: PropsOptions<VT>): Props<VT>
function props(): Props<'value'>
function props({ valueProp = 'value' }: PropsOptions<ValueType | undefined> = {}) {
  return {
    [valueProp]: 'value',
    other: 'other',
  }
}

Play