#javascript #typescript #types
#javascript #typescript #типы
Вопрос:
У меня есть этот интерфейс:
export interface IScene<R extends string> {
path: R;
params?: SceneParams;
}
Интерфейс SceneParams:
export interface SceneParams {
[key: string]: string;
}
Это работает абсолютно нормально, когда я создаю сцену, подобную:
interface PostDetailScene extends IScene<PostRoute.Detail> {
params: PostDetailSceneParams;
}
Параметры PostDetailSceneParams:
export interface PostDetailSceneParams extends SceneParams {
postId: string;
}
Весь этот код получает правильную проверку типа:
// CORRECT
getPathWithParams({
path: PostRoute.Detail,
params: { postId: '4' },
});
getPathWithParams({
path: UserRoute.List,
});
getPathWithParams({
path: UserRoute.List,
params: undefined,
});
// ERROR
getPathWithParams({
path: PostRoute.Detail,
params: undefined,
});
getPathWithParams({
path: PostRoute.Detail,
});
getPathWithParams({
path: UserRoute.List,
params: { wrongParam: 'value' },
});
Теперь у меня есть сцена, в которой я не хочу передавать какие-либо реквизиты. Эта сцена является UserListScene:
interface UserListScene extends IScene<UserRoute.List> {
params?: never;
}
Видите ли, я должен явно ввести params?: never
(или params?: undefined
— я также не знаю, какой тип мне следует использовать здесь, потому что здесь параметры действительно никогда не будут / не должны передаваться — но с never
компилятор также удовлетворяется значением undefined, поэтому я не вижу такой большой разницы)
Мой вопрос таков: есть ли решение для изменения интерфейса IScene, чтобы мне не приходилось вводить, params?: never
или params?: undefined
когда для этой сцены нет параметров?
Я просто хочу написать:
interface UserListScene extends IScene<UserRoute.List> {}
или:
type UserListScene = IScene<UserRoute.List>;
Редактировать:
Эта функция также должна корректно проверять тип:
export function getPathWithParams(scene: Scene): string {
if (!scene.params) {
return scene.path;
}
let pathWithParams: string = scene.path;
const paramsAsString = Object.keys(scene.params);
paramsAsString.forEach((param: string) => {
pathWithParams = pathWithParams.replace(`:${param}`, scene.params[param]);
});
return pathWithParams;
}
Ответ №1:
Используйте два интерфейса (поскольку на самом деле это то, что у вас действительно есть здесь):
export interface IScene<R extends string> {
path: R;
}
export interface ISceneWithParams<R extends string> {
path: R;
params: SceneParams;
}
Комментарии:
1. Но тогда мне приходится выбирать между интерфейсами to каждый раз, когда я создаю сцену. Я просто хочу иметь один интерфейс для обоих случаев. Кроме того, я отредактировал свой ответ и добавил функцию, которая также должна корректно проверять тип.