Pull to refresh

Comments 4

Совпадение или нет, но недавно как раз изучал сужение типов.
И появился вопрос.

Как сузить тип второго и/или последующего независимого аргумента функции в зависимости от типа первого аргумента?

Пример
enum ShapeType {
    Circle = 'circle',
    Square = 'square',
};

type SquareColor = 'black' | 'white';
type CircleColor = 'red' | 'blue';

type Circle = {
    type: ShapeType.Circle;
    color: CircleColor;
    radius: number;
}

type Square = {
    type: ShapeType.Square;
    color: SquareColor;
    sideLength: number; 
}

type Shape = Circle | Square;

const isSquare = (shape: Shape): shape is Square => {
    return shape.type === ShapeType.Square;
}

const repaintShape = (shape: Shape, param: SquareColor | CircleColor): Shape => {
    if (isSquare(shape)) {
        // param всё ещё CircleColor | SquareColor хоть shape теперь верно Square
        // понятно что у TS нет возможности догадаться
        // какой тип param нам нужен, как эту проблему решить?
    }
}


То же самое с оверлоадом казалось бы раз мы сузили тип shape до Square, почему TypeScript не может подсказать что param это SquareParam, ведь кажется теперь-то у него для этого все возможности есть поскольку задекларированы возможные комбинации параметров? Или нет?
function repaintShape(shape: Circle, param: CircleColor): Circle
function repaintShape(shape: Square, param: SquareColor): Square
function repaintShape(shape: Shape, param: CircleColor | SquareColor): Shape {
    if (isSquare(shape)) {
        // shape теперь Square но param всё ещё CircleColor | SquareColor
    }
}

В вашем случае typescript не может связать shape и param, для него это разные вещи и он понятия не имеет что именно вы хотите с ними делать. У вас буквально указано, что аргументами могут быть Shape и вот такие цвета, поэтому typescript и допускает вызов Circle с SquareColor


Если вы хотите именно связать shape и param на уровне вызова функции, чтобы при передаче Circle в качестве param можно было указывать лишь CircleColor, а при Square только SquareColor, то могу рекомендовать сделать это через generic


const repaintShape = <T extends Shape>(
  shape: T,
  param: T['color']
): Shape => {
  // ...
};

В таком случае любая Shape будет требовать свой цвет

Должно быть: «И последнее слово о сужении по истинности: логические отрицания с ! отфильтровываются из отрицательных ветвей.»
Вместо: «Напоследок, рассмотрим пример использования логического оператора „НЕ“:»

Странная тема про сужение. Странна тем, что solid подход и не встретил бы этих проблем имхо

Sign up to leave a comment.