Как предоставить значение по умолчанию для параметра типа объединения без получения "может быть создан с другим подтипом ограничения" - PullRequest
1 голос
/ 28 октября 2019

В качестве продолжения моего предыдущего вопроса ...

Можно ли указать значение по умолчанию для 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

Воспроизведение


Когда я пытаюсь это сделать:

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'.

Iпонять эту ошибку ( 1 , 2 , 3 , 4 ) в целом, но все же не всегда знаете лучший способ устранить эту ошибку.

Есть ли простой способ сделать то, что я пытаюсь сделать?

Просто кажется, что должен быть простой способ предоставитьзначение по умолчанию, но, может быть, значения по умолчанию просто не очень хорошо сочетаются с ограничениями универсального типа?

Тип по умолчанию для универсального типа?

Я пробовал это:

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

но, конечно, получена та же ошибка, потому что T все еще может быть defaultValue, если указан конкретный 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 голосов
/ 29 октября 2019

Основываясь на комментарии Тициана Черникова-Драгомира, мы можем сделать это довольно просто, используя перегрузки функций:

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

...