TypeScript: вывод типа общий тип «prop» в условии выдает ошибку

#typescript #type-inference #typescript-generics

#typescript #вывод типа #typescript-generics

Вопрос:

Я столкнулся со следующей проблемой (абстрагированной) в проекте, и я действительно смущен, если я делаю что-то не так:

 const fooState = {
  normal: {
    normalProp: "string",
  },
  normal2: {
    normalProp: 0,
  },
  weird: {
    weirdProp: "anything",
  },
};

type fooKeys = keyof typeof fooState;

export const getFooState = <T1 extends fooKeys>(arg: T1) => {
  const foundState = fooState[arg];
  if ("weirdProp" in foundState) {
    console.log(foundState.weirdProp); // This line throws an error, even though it is a practical possibility.
  }

  return foundState;
};
  

Кода должно быть достаточно, чтобы объяснить мою проблему. Моя цель — обработать конкретный случай по-другому, когда foundState объект имеет определенное свойство.

В моем примере, если аргумент arg передается как "weird" , журнал консоли будет / должен сработать, но TS выдает ошибку. Почему это?

Я ценю все ответы.

Ответ №1:

Похоже, что typescript нуждается в явной защите типа для вашего случая. Динамический способ определения простой одноуровневой функции защиты типа — это

 function dynamicCheckTopLevel<V>(a:any,b:V): a is V {
    let keys = Object.keys(b)
    return keys.every(k => k in a)
}
  

Вы также могли бы использовать защиту типа специально для этого prop, тогда вы можете четко указать тип, а не выводить из переданного объекта, который имеет примерное значение для ключа

 function weirdCheck(x:any): x is {weirdProp:any}{
  return x.weirdProp;
}
  

затем ошибка исчезает

 export const getFooState = <T1 extends fooKeys>(arg: T1) => {
  const foundState = fooState[arg];
  if (dynamicCheckTopLevel(foundState, {weirdProp:5})) { //had to give weirdProp a value, for your purpose it can be anything
    console.log(foundState.weirdProp); 
  }

  return foundState;
};
  

Если вы хотите перейти к более глубокой защите динамического типа, вы можете использовать

 function dynamicDeepCheck<V>(a:any,b:V): a is V {
    let keys = Object.keys(b) as Array<keyof V>
    return keys.every(key => {
      if(typeof b[key] === "object"){ 
        return dynamicDeepCheck(a[key], b[key])
      }
      return (a[key] amp;amp; typeof a[key] === typeof b[key])
    })
}
  

В защите типа верхнего уровня я опустил проверку соответствия значению typeof, поскольку ваше условие защиты неявного типа, похоже, не заботилось о значении prop.

Ссылка на игровую площадку