Type Guard Typescript неправильно выводит параметры функции остановки

У меня есть пример Typescript с параметрами типа guard и функцией rest:

interface BaseProps {
  username: string;
  password: string;
}

type Props = BaseProps & (
  | {isAdmin: true, adminName: string} 
  | {isAdmin: false}
)


// Doesn't works
const myFn = ({isAdmin, ...rest}: Props) => {
  if(isAdmin === true) {
    rest.adminName; // Property 'adminName' does not exist on type '{ username: string; adminName: string; } | { username: string; }'.
  }
}

// It works
const myFn2 = (args: Props) => {
  if(args.isAdmin === true) {
    args.adminName;
  } 
}

Что не так с остальными параметрами и охраной типов?

TS Детская площадка


ОБНОВЛЕНИЕ РЕШЕНИЯ:

Я нашел решение, используя Assert Functions чтобы решить проблему.

declare function assertType<T>(val: unknown): asserts val is T;

const myFn = ({password, isAdmin, ...rest}: Props) => {

  if(isAdmin === true) {
    
    assertType<Omit<Props & {isAdmin: true}, keyof Props>>(rest);

    rest.adminName; // <=== HERE

    rest.username;

    // Should be error
    rest.password;
  }
}

TS Детская площадка

1 ответ

Тип Props является

{имя пользователя: строка, isAdmin: true, adminName: строка} | {имя пользователя: строка, isAdmin: false }

Когда вы утверждаете ценность isAdmin на объекте типа Prop (например, if оператор), машинописный текст может сузить фактический тип между { username: string, isAdmin: true, adminName: string } и { username: string, isAdmin: false }.

Если вы удалите isAdmin путем деструктурирования тип rest становится

{имя пользователя: строка, adminName: строка} | {имя пользователя: строка}

Ценности isAdmin и rest стать некоррелированными, и это единственный способ сузить тип rest состоит в том, чтобы утверждать наличие adminName свойство.

Возможно, вам не стоит использовать параметры отдыха для этого конкретного случая. Вы также можете вручную использовать rest переменная внутри if.

Другие вопросы по тегам