TypeScript에서 ANY를 사용할 때의 비밀 함정
15222 단어 typescriptweb
무엇입니까?
TypeScript로 작업하는 경우 the
any
type을 사용하게 될 가능성이 있습니다. any
기본적으로 유형 검사를 해제하고 해당 변수를 모든 용도로 사용할 수 있습니다. any
변수에서 모든 메서드를 호출할 수 있으며 모두 any
도 반환합니다. 코드베이스의 모든 항목에 대한 유형을 작성할 수 없을 때 유용합니다.let obj: any = { x: 0 };
// None of these lines of code are errors
const foo: any = obj.foo();
obj();
obj.bar = 100;
함수 오버로드란 무엇입니까?
TypeScript에는 또 다른neat feature called function overloads . 일부 JavaScript 함수는 제공한 인수에 따라 다른 결과를 반환하며, 이는 여러 함수 유형을 서로 위에 작성하여 TypeScript에서 나타낼 수 있습니다. 한 번에 하나의 함수 시그니처만 일치시킬 수 있습니다. 일치하는 오버로드는 함수에 제공하는 인수에 따라 결정됩니다. The first applicable overload will always be chosen .
function convertType(value: string): number;
function convertType(value: number): string;
function convertType(value: string | number): number | string {
if (typeof value === 'number') {
return value.toString();
} else {
return parseFloat(value);
}
}
const num: number = convertType('number');
const str: string = convertType(num);
배열에 오버로딩 사용
일부 함수는 어떤 방식으로 배열을 변환하고 동일한 길이와 약간 수정된 유형의 배열을 반환하려고 합니다. A good example of this is
Promise.all
, 약속 배열을 값 배열로 해결되는 단일 약속으로 변환합니다.generic function definitions 을 사용하여
Promise.all
에 전달된 배열의 유형을 유추할 수 있습니다. 그러나 결과 유형은 위치 데이터가 없는 배열이 됩니다.class Promise {
static all<T>(array: (T | Promise<T>)[]): T[];
}
Promise.all([Promise.resolve(10), Promise.resolve('hello world')]).then(
(result) => {
// result's type is (number | string)[]
// @ts-expect-error: Type 'string' is not assignable to type 'number'.
const num: number = result[0];
}
);
TypeScript는 특정 배열 항목의 유형을 유추할 수 있지만 길이를 하드코딩해야 합니다. 오버로딩을 사용하면 다양한 배열 길이에 대해 몇 가지 변형을 가질 수 있습니다.
class Promise {
static all<A, B, C>(
array: [A | Promise<A>, B | Promise<B>, C | Promise<C>]
): [A, B, C];
static all<A, B>(array: [A | Promise<A>, B | Promise<B>]): [A, B];
static all<A>(array: [A | Promise<A>]): [A];
// fallback to unknown length
static all<T>(array: (T | Promise<T>)[]): T[];
}
Promise.all([Promise.resolve(10), Promise.resolve('hello world')]).then(
(result) => {
// result's type is [number, string]
// This line is no longer an error
const num: number = result[0];
}
);
그러나 너무 많은 오버로드만 작성할 수 있습니다. 결국 위와 같이 길이를 알 수 없는 배열로 폴백해야 합니다. TypeScriptofficial type definitions for
Promise.all
는 배열을 최대 길이 10까지 하드코딩하고 그 이후에는 폴백합니다.과부하로 인해 문제가 발생하는 방법
any
는 모든 유형과 일치하며 함수 오버로드는 적용 가능한 첫 번째 오버로드를 사용합니다. 이 두 가지 사실은 유형이 any
인 변수를 오버로드가 있는 함수에 전달할 때 문제를 일으킵니다.function convertType(value: string): number;
function convertType(value: number): string;
function convertType(value: string | number): number | string {
if (typeof value === 'number') {
return value.toString();
} else {
return parseFloat(value);
}
}
const num: any = 10;
// @ts-expect-error: Type 'number' is not assignable to type 'string'.
const str: string = convertType(num);
첫 번째 오버로드는
any
형식의 변수를 전달할 때 항상 사용됩니다. 해당 서명에 적용할 수 있기 때문입니다. 나중에 더 일반적인 서명이 있더라도 첫 번째 오버로드가 선택됩니다. 더 일반적인 서명이 전달하는 모든 변수와 일치하기 때문에 오버로드 순서를 되돌릴 수 없습니다. 내가 아는 한, 변수가 유형any
인 경우에만 일치하는 서명을 작성할 수 없습니다. 양방향으로.Promise.all
의 경우 첫 번째 함수 오버로드 서명은 하드코딩된 길이가 10인 배열입니다. 그러면 any
가 전달되고 결과 유형이 정확히 10unknown
의 배열이 되는 이와 같은 혼란스러운 버그가 발생할 수 있습니다. ) 에스.에반™
알겠습니다. 왜 *정확히* 10개의 `unknown` 배열인 `any` 맵을 기다리고 있습니까?
오후 22:31 - 2020년 10월 12일
0
1
미래 솔루션
배열 길이를 하드코딩하는 것은 좋지 않습니다. 너무 많은 변형만 지원할 수 있기 때문입니다. TypeScript 4.0에는 “variadic tuple types” 이라는 새로운 기능이 도입되어 정확한 배열 인수를 캡처하고 변환할 수 있습니다. Future type definitions for
Promise.all
은 모든 함수 오버로드를 단일 함수 서명으로 대체하여 any
버그를 완전히 제거할 수 있습니다.TypeScript는 향후 함수 오버로드로 전달
any
하기 위한 특수 처리를 추가할 수도 있습니다. 기존 문제를 알고 있거나 내가 놓친 것을 본 경우 알려주세요.
Reference
이 문제에 관하여(TypeScript에서 ANY를 사용할 때의 비밀 함정), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/notwoods/the-secret-trap-when-using-any-in-typescript-2g85텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)