1

I have this interface:

export interface IScene<R extends string> {
  path: R;
  params?: SceneParams;
}

SceneParams interface:

export interface SceneParams {
  [key: string]: string;
}

This works totally fine when I create a scene like:

interface PostDetailScene extends IScene<PostRoute.Detail> {
  params: PostDetailSceneParams;
}

PostDetailSceneParams:

export interface PostDetailSceneParams extends SceneParams {
  postId: string;
}

All these code gets correct type checking:

// 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' },
});

Now I have a scene where I don't want to pass any props. This scene is the UserListScene:

interface UserListScene extends IScene<UserRoute.List> {
  params?: never;
}

You see I have to explicitly type params?: never (or params?: undefined - I also don't know which type I should use here because here the params would/should really never get passed - but with never the compiler gets also satisfied with undefined so I don't see that much difference)

My question is: Is there a solution for changing the IScene interface so that I don't have to type params?: never or params?: undefined when there are no params for this scene?

I just want to write:

interface UserListScene extends IScene<UserRoute.List> {}

or:

type UserListScene = IScene<UserRoute.List>;

EDIT:

This function should also get correct type checking:

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 Answer 1

1

Use two interfaces (as truly that is what you really have here):

export interface IScene<R extends string> {
  path: R;
}

export interface ISceneWithParams<R extends string> {
  path: R;
  params: SceneParams;
}
Sign up to request clarification or add additional context in comments.

1 Comment

But then I have to decide between to interfaces every time I create a Scene. I just want to have one interface for both cases. Also, I edited my answer and add a function that should also get correct type checking.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.