Супертипы и подтипы в typescript
Делаю приложение на react/typescript. В приложении есть свой ui-kit с переиспользуемыми компонентами - Select, Input, Button и тд. И ,соответсвенно, разные потребители этих компонентов со своими типами.
Не получается затипизировать Select. Упрощенный пример - https://codesandbox.io/s/silly-albattani-h95cfj
Тип у пропа selectedItem:
type SelectedItem = { value: string | number; label?: string; };
А у пропа onChange:
(option: SelectedItem) => void
Там, где используется этот компонент, я хочу прокинуть в проп selectedItem такой тип
type City = { value: string; label: string }
А в проп onChange:
(city: City) => void
Я ожидаю, что типы описанные в компоненте Select будут являться супертипами, тогда:
- Тип City будет подтипом для SelectedItem
- Тип (city: City) => void будет подтипом для (option: SelectedItem) => void
Первый пункт срабатывает, а второй почему то нет
Как будто бы ts считает (city: City) => void супертипом, а тип (option: SelectedItem) => void подтипом
Ответы (2 шт):
Компонент ожидает функцию, которая может принимать как number так и string.
Ты передаешь функцию, которая может принимать только string. Поэтому ее нельзя использовать.
На примере:
есть тип
type P = string | number;
есть тип функции
type Callback = (param: P) => void;
И переменная с этим типом: var cb: Callback.
предположим, что в эту переменную можно записать функцию принимающую только string
var cb:Callback = (p:string) => console.log(p.length);
В этом случае возникает проблема с вызовом cb(10).
тип
Callback- разрешает такой вызов, потому что тип параметра может быть либо строкой либо числом.Присвоенная функция - не разрешает, так как требует, чтобы параметр был только строкой.
Как следствие, само присваивание тоже не разрешено.
Ты даже не все параметры передал, и вообще фигня в типах. Пример-то надо было до нормального состояния сначала довести, а потом спрашивать.
В общем, у меня получилось такое. Но если бы ты не пропустил параметр options, вероятно, могло бы и что-то более простое заработать, но мне теперь лень.
https://codesandbox.io/s/confident-currying-t8pi8w?file=/src/ui-kit/Select.tsx
export type SelectedItem<T extends number | string> = {
value: T;
label?: string;
};
type SelectProps<T extends SelectedItem<any>> = {
selectedItem: T;
onChange: (opt: T) => void;
options: T[];
};
export function Select<T extends SelectedItem<any>>({ selectedItem, onChange, options }: SelectProps<T>) {
return null;
}
import "./styles.css";
import { useState } from "react";
import { Select } from "./ui-kit/Select";
type City = { value: string; label: string };
const cities: City[] = [];
export default function App() {
const [value, setValue] = useState<City>({
value: "1",
label: "Moscow"
});
const handleChange = (opt: City) => {
setValue(opt);
};
return (
<div className="App">
<Select onChange={handleChange} selectedItem={value} options={cities} />
</div>
);
}
