TypeScript의 일반 유형 가드에 대한 주의 사항(및 솔루션)입니다.
TypeScript 언어는 타입 가드 🛡️라는 개념을 사용합니다. 이는 더 안전한 코드를 작성하고 화나고 불평하는 컴파일러를 처리하는 데 도움이 되는 영리한 컴파일러 기능입니다.
컴파일러는 가드를 사용하여 값 유형을 좁히고 IntelliSense 제안을 제공합니다.
주어진 상속 모델이 있다고 가정해 보겠습니다.
class Vehicle {
brand: string;
}
class Aircraft extends Vehicle {
usage: 'civil' | 'military';
}
class Car extends Vehicle {
drive: 'AWD' | 'FWD' | 'RWD';
}
속성 측면에서 확장
secretVehicle
하는 것으로 알고 있는 Vehicle
객체가 제공됩니다. 그러나 개체는 이러한 클래스의 인스턴스가 아닙니다.따라서
instanceof
접근 방식은 왼쪽 피연산자가 인스턴스여야 하므로 작동하지 않습니다.if (secretVehicle instanceof Car) {
console.log(`This is a car with ${secretVehicle.drive} drive`);
// TypeScript doesn't complain, but this will never print!
}
대신 우리가 할 수 있는 일은
secretVehicle
서브클래스의 모든 속성이 있는지 확인하는 것입니다.리플렉션을 사용하거나 해당 클래스의 실제 인스턴스를 만들고
Object.keys()
를 사용하여 키를 조회하여 이를 수행합니다.export const hasAllKeys =
<T>(obj: Record<string, any>, cls: new () => T): obj is T => {
const properties = Object.keys(new cls());
for (const p of properties) {
if (!(p in obj)) return false;
}
return true;
};
그런 다음 가드를 사용하여 TypeScript에
secretVehicle
가 실제로 주어진 유형임을 확인할 수 있습니다.if (hasAllKeys(secretVehicle, Car)) {
console.log(`This is a car with ${secretVehicle.drive} drive`);
}
if (hasAllKeys(secretVehicle, Aircraft)) {
console.log(`This is a ${secretVehicle.usage} aircraft`);
}
그러나 일부 극단적인 경우 이 솔루션은 문제가 있습니다. 사용자 지정 생성자가 있는 클래스와 함께 사용하면 속성을 잘못 확인할 수 있습니다.
더욱이 때로는 단순히 우리에게 필요한 것이 아닙니다. 우리가 얻는 입력 데이터는 종종
Partial<T>
대신 T
이며, 이는 일부 속성이 누락될 수 있음을 의미합니다(예: id
).이에 대응하기 위해 모든 속성 대신 특정 속성을 확인하는 가드를 사용합시다.
export const hasKeys =
<T>(
obj: Record<string, any>,
properties: (keyof T)[]
): obj is T =>
properties.filter(p => p in obj).length == properties.length;
// functional approach
TypeScript 컴파일러는 지정하고 싶지 않은 경우 자체적으로
T
알아낼 만큼 충분히 영리합니다.예를 들어,
hasKeys(secretVehicle, ['usage'])
는 T
가 {usage: any}
유형이라고 추론하므로 if 문 내부에서 usage
키를 사용할 수 있습니다.if (hasKeys(secretVehicle, ['usage'])) {
console.log(`
Not sure what this is,
but it has a ${secretVehicle.usage} usage!
`);
}
아아, 이것은 우리가
any
유형의 값에 대해 작업하도록 합니다.해당 키의 유형을 전달할 수 있습니다.
hasKeys<{usage: 'civil' | 'military'}>(secretVehicle, ['usage']);
또는 단순히 전체 클래스를 전달하십시오.
hasKeys<Aircraft>(secretVehicle, ['usage']);
이렇게 하면 키를 정의할 때 IntelliSense 제안도 제공됩니다!
그러나 두 하위 클래스에 동일한 필드가 있지만 유형이 다른 경우에는 어떻게 될까요? 문제가 더 복잡해지고 리플렉션을 사용해야 할 수도 있습니다.
그러나 기본 클래스에
type
필드를 지정하여 유형을 쉽게 구분함으로써 이 문제를 극복할 수 있습니다.class Vehicle {
brand: string;
type: 'Car' | 'Aircraft';
}
const ofType =
<T>(
obj: Record<string, any> & {type?: string},
cls: new () => T
): obj is T =>
obj.type == (new cls()).constructor.name;
// or use another argument for the type field
if (ofType(secretVehicle, Car)) {
console.log(`This is a car with ${secretVehicle.drive} drive`);
}
TypeScript는 강력한 언어이며 이러한 구문을 사용하면 최대한 활용하는 데 도움이 됩니다.
dev.to
커뮤니티에 대한 저의 첫 번째 기고문을 읽어주셔서 감사합니다.즐거운 코딩! 🎉
Reference
이 문제에 관하여(TypeScript의 일반 유형 가드에 대한 주의 사항(및 솔루션)입니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/judehunter/the-caveats-and-solutions-to-generic-type-guards-in-typescript-2o7a텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)