Типографские дженерики с условными типами

#typescript #generics #typescript-generics #conditional-types

Вопрос:

У меня есть тип, содержащий некоторые условные обозначения (обратите внимание, что это не мой фактический код, а урезанная версия, которая пытается выделить проблему с наименьшим количеством кода).

 type A<T> = {
  prop: T;
  value:
    T extends string ? { a: T, b: T } :
    T extends number ? { y: T, z: T } :
    never
}
 

Создание экземпляров переменных с этим типом работает нормально. Например.

 // works
const a_string: A<string> = {
  prop: '',
  value: { a: '', b: ''}
}

// works
const a_number: A<number> = {
  prop: 0,
  value: { y: 1, z: 1}
}

// errors (as expected)
const a_mistake: A<number> = {
  prop: 0,
  value: { a: '', b: '' } <-- Should be { y:number, z: number }
}
 

Моя проблема заключается в том, что я пытаюсь создать эту функцию:

 function myFunc<T extends string>(prop: T): A<T> {
  return {
    prop,
    value: { a: prop, b: prop }
  }
}
 

Я не могу понять, почему это не работает. Машинописный текст жалуется, что то, что я возвращаю, не может быть присвоено:

 Type '{ a: T; b: T; }' is not assignable to type 'T extends string ? { a: T; b: T; } : T extends number ? { y: T; z: T; } : never'.ts(2322)
union.ts(33, 3): The expected type comes from property 'value' which is declared here on type 'A<T>'
 

Хоть убей, я не могу понять, почему?

Комментарии:

1. Поскольку ваша T расширенная строка, почему бы вам просто не использовать A<string> ее в качестве возвращаемого типа? Рассматривайте A<T> как тип, который не был оценен, это просто условный тип. И тип состояния сам по себе не может быть присвоен value

2. Пример не охватывает все фактические случаи, которые охватывает мой код. У меня есть сложные объекты, которые передаются (не только примитивы , такие как string и т. number Д.). Жесткое кодирование возвращенного A значения A<Object> означает, что я теряю информацию о типе. например, если T были { some: 'complex', type: 2 }

3. Я думаю, что стоит создать словарь для всех ваших случаев вместо условного ввода

4. Можете ли вы объяснить подробнее?

5. Как я понял myFUnc , содержит a switch с разными случаями, верно?

Ответ №1:

Я не знаю ответа на вопрос, почему это не работает, но по какой-то причине typescript не может определить правильный тип свойства value. Способ решить эту проблему-использовать утверждения типа, поскольку вы знаете, что prop расширения string :

 function myFunc<T extends string>(prop: T) {
    return {
        prop,
        value: { a: prop, b: prop },
    } as A<T>;
}
 

Ответ №2:

Я немного переусердствовал.

Все, что вам нужно сделать, это переоценить свою функцию.

 type A<T> = {
    prop: T;
    value:
    T extends string ? { a: T, b: T } :
    T extends number ? { y: T, z: T } :
    never
}

function myFunc<Prop extends string | number>(prop: Prop): A<Prop>
function myFunc<Prop extends string | number>(prop: Prop) {
    return {
        prop,
        value: { a: prop, b: prop }
    }
}


const result = myFunc('sdf').value.a // ok
const result2 = myFunc(42).value.y // ok
 

Игровая площадка

Я предполагаю, что у вас много switch случаев в этой функции, в противном случае вам даже не нужен общий параметр.