이 인터페이스가 있습니다.
export interface ICRUDService<T extends IModel> {
save(item: T): Promise<void>;
save(items: T[]): Promise<void>;
save(item: IRemoteData<T>): Promise<void>;
save(items: IRemoteData<T>[]): Promise<void>;
save(item: Partial<T>): Promise<void>;
}
및 구현 :
export abstract class AbstractCRUDServiceImpl<T extends IModel> implements ICRUDService<T> {
async save(item: T): Promise<void>;
async save(items: T[]): Promise<void>;
async save(item: IRemoteData<T>): Promise<void>;
async save(items: IRemoteData<T>[]): Promise<void>;
async save(item: Partial<T>): Promise<void>;
async save(item: any): Promise<void> {
if (typeof item === T)
// ...
}
}
그러나 그것은 말한다 :
'T'는 유형만을 의미하지만 여기서는 값으로 사용됩니다 .ts (2693) '
이 문제를 해결하는 올바른 방법은 무엇입니까?
코드가 실제로 실행 중이면 모든 입력 정보가 사라집니다. 따라서 런타임에 객체가 무엇인지 파악하기 위해 유형에 의존 할 수 없습니다.
대신 값에 원하는 유형 과 동일한 기능 이 있는지 확인해야합니다 .
둘째, 구현 함수의 인수는 재정의의 모든 유형을 합친 유형이어야합니다.
IModel
및 다음 과 IRemoteData
같이 설정되어 있다고 가정 해 보겠습니다 .
interface IRemoteData<T> {
remoteData: T
}
interface IModel {
id: number
}
이제 다음과 같은 구현을 갖게됩니다.
export abstract class AbstractCRUDServiceImpl<T extends IModel> implements ICRUDService<T> {
async save(item: T): Promise<void>;
async save(items: T[]): Promise<void>;
async save(item: IRemoteData<T>): Promise<void>;
async save(items: IRemoteData<T>[]): Promise<void>;
async save(item: Partial<T>): Promise<void>;
async save(items: IRemoteData<T> | T): Promise<void>; // Added this override
async save(item: T | T[] | IRemoteData<T> | IRemoteData<T>[] | Partial<T>): Promise<void> {
if (Array.isArray(item)) {
// item is array in this scope, iterate over each item and save them
for (const singleItem of item) {
await this.save(singleItem)
}
} else {
// item is not an array in this scope
if ('id' in item) {
item // T | Partial<T>
} else {
item // IRemoteData<T>
}
}
}
}
해당 조건부의 각 분기에서 해당 유형을 처리합니다.
유형과 비교하지 않지만 원하는 유형의 기능이 있는지 확인합니다. 를 사용 Array.isArray()
하여 배열인지 확인할 수 있으며 조건부 유형 스크립트에서 사용될 때 그것이 배열임을 알 수 있으며 해당 유형은 더 이상 공용체에서 배열이 아닌 유형이 될 수 없습니다.
를 사용 'propName' in item
하여 원하는 유형 중 하나에 만 존재할 수있는 속성을 정의하는지 테스트 할 수 있습니다 .
그런 다음 else
절을 사용하여 아직 필터링하지 않은 모든 유형과 일치 시킬 수 있습니다 .
이제 추가 재정의에 유의하십시오.
async save(items: IRemoteData<T> | T): Promise<void>; // Added this override
이것은 조건부의 배열 처리 분기에 필요합니다. 문제는 그것이 배열이라는 것을 알고 나면 그것이 배열 인 것을 알지 못한다는 것입니다. 따라서 항목을 반복 할 때 각 항목의 유형은 다음과 같습니다.
T | IRemoteData<T>
따라서 특정 경우를 처리하려면 과부하가 필요합니다.
async save(items: IRemoteData<T> | T): Promise<void>; // Added this override
또는 재정의를 완전히 제거 할 수 있습니다. 오버라이드는 유형의 통합이 될 수있는 인수가 하나만있을 때 유용하지 않으며 훨씬 더 유용한 특정 인수 시그니처가 다른 유형을 반환합니다. 이것은 하나의 함수 정의만으로는 할 수없는 일입니다.
예를 들면 :
function foo(a: number): string
function foo(a: string): number
function foo(a: number|string): number|string {
if (typeof a === 'string') {
return 123
} else {
return 'a string'
}
}
이 오버로드는 특정 인수 유형을 특정 반환 유형에 연결합니다. 그러나 당신의 함수는 그것을 필요로하지 않으며, 인수가 단순히 많은 것들을 결합한 단일 함수로 표현 될 수 있습니다.
이것이 작동한다는 것을 의미합니다.
export abstract class AbstractCRUDServiceImpl<T extends IModel> {
async save(item: T | T[] | IRemoteData<T> | IRemoteData<T>[] | Partial<T>): Promise<void> {
if (Array.isArray(item)) {
// item is array in this scope, iterate over each item and save them
for (const singleItem of item) {
await this.save(singleItem)
}
} else {
// item is not an array in this scope
if ('id' in item) {
item // T | Partial<T>
} else {
item // IRemoteData<T>
}
}
}
}
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다