'인터페이스' 유형의 인수는 '인터페이스' 유형의 매개변수에 할당할 수 없습니다.
13064 단어 typescript
내가 working on a refactor NgRx 프로젝트에서 NgRx 감속기
on
- variadic tuple types 🥳 내에서 N개의 액션 핸들러createReducer
를 허용하기 위해 🥳 동안 TypeScript 문제가 발생했습니다. 이미 부딪쳤습니다.문제는 "'인터페이스' 유형의 인수를 '인터페이스' 유형의 매개변수에 할당할 수 없습니다"라는 메시지를 표시하는 컴파일 시간 오류입니다. 내가 했던 것처럼 전체 오류 메시지를 읽지 않으면 문제, 발생 이유 및 이 오류를 해결하는 방법을 이해하는 데 시간이 걸릴 수 있습니다.
내 이해에 따르면 다음과 같은 래퍼 메서드가 있을 때 오류가 나타납니다.
아래 스니펫은 가장 간단한 방법으로 문제를 보여줍니다.
// The `Callback<T>` interface is used in the `wrapper` method as well as the `callback` method.
interface Callback<T extends object> {
(arg: T): any
}
function wrapper<T extends object>(callback: Callback<T>): any {
return callback({} as T)
}
function callback<T extends object>(cb: () => T): Callback<T> {
return cb
}
이러한 함수는 사용할 때 다음과 같은 결과를 제공합니다.
// --- INVALID --- //
const givesAnError = wrapper<{ prop?: string }>(callback(() => ({ prop: '' })))
// |> Argument of type 'Callback<{ prop: string; }>' is not assignable to parameter of type 'Callback<{ prop?: string | undefined; }>'.
// |> Types of property 'prop' are incompatible.
// |> Type 'string | undefined' is not assignable to type 'string'.
// --- VALID --- //
// Types are 100% identical
const works = wrapper<{ prop: string }>(callback(() => ({ prop: '' })))
// Provide the same generic to the callback method
const worksCallbackGeneric = wrapper<{ prop?: string }>(a
callback<{ prop?: string }>(() => ({ prop: '' })),
)
// A type assertion on the return value of the callback
const worksTypeAssertion = wrapper<{ prop?: string }>(
callback(() => ({ prop: '' } as { prop?: string })),
)
이제 이상한 부분은
callback
메서드가 동일한 유형의 입력 매개변수를 수락하면 컴파일된다는 것입니다.그러나 인수가 사용되는 경우에만.
function callbackWithInput<T extends object>(cb: Callback<T>): Callback<T> {
return cb
}
// --- VALID --- //
// Note the argument `_arg` isn't used but helps to make this compile
const works = wrapper<{ prop?: string }>(
callbackWithInput((_arg) => ({ prop: '' })),
)
// --- INVALID --- //
// Same but without an argument gives the same compile error as before
const stillDoesntWork = wrapper<{ prop?: string }>(
callbackWithInput(() => ({ prop: '' })),
)
// |> Argument of type 'Callback<{ prop: string; }>' is not assignable to parameter of type 'Callback<{ prop?: string | undefined; }>'.
// |> Types of parameters 'input' and 'input' are incompatible.
// |> Type '{ prop?: string | undefined; }' is not assignable to type '{ prop: string; }'
내가 볼 수 있었던 것은 TypeScript가 더 이상 제네릭의 인터페이스를 올바르게 추론할 수 없다는 것입니다.
솔직히 말해서, 나는 그 이유를 모르겠고 서명이 같은 유형을 가지고 있기 때문에 이것이 컴파일될 것으로 예상합니다.
위의 사용 예에서 볼 수 있듯이 이 작업을 수행할 수 있지만 서명이나 콜백 메서드가 호출되는 방식을 변경해야 합니다. 소비자의 관점에서 이것은 나쁘고 NgRx를 사용하는 사람들에게는 엄청난 변화가 되었을 것입니다.
수정 사항으로 NgRx의 Iintroduced a new generic에서 TypeScript의 간섭을 돕습니다. 처음에는 이것이 수정된 것처럼 보였지만
on
메서드의 서명이 변경되었기 때문에 숨겨진 주요 변경 사항이 도입되었습니다.Noteworthy to mention that if you're adding a generic to only use it once, you're probably doing something wrong. This rule "Type Parameters Should Appear Twice" is explained in The Golden Rule of Generics, written by .
운 좋게도 소비자에게 영향을 미치지 않는 제공a better solution.
이 문제를 올바르게 해결하는 솔루션은 TypeScript가 유형을 유추하도록 돕는 것입니다. 이를 위해 제네릭의 엄격함을 조정할 수 있습니다. 제네릭을 직접 사용하는 대신
keyof
를 사용하여 매핑된 유형을 만들 수 있습니다.interface Callback<T extends object> {
(
input: {
[P in keyof T]?: T[P]
},
): S
}
여기서 또 다른 이상한 부분은 NgRx 유형에서 Alex가 제네릭 속성을 잠재적으로
undefined
로 입력할 필요가 없다는 것입니다(here에서 볼 수 있듯이).따라서 이 블로그 게시물은 우리에게 약간의 불분명함을 남기지만 이 문제에 대한 해결책을 제공합니다.
이 재생산을 가지고 놀려면 TypeScript Playground link을 참조하십시오.
Twitter에서 나를 팔로우하세요. | 구독하기 Newsletter | timdeschryver.dev에 원래 게시되었습니다.
Reference
이 문제에 관하여('인터페이스' 유형의 인수는 '인터페이스' 유형의 매개변수에 할당할 수 없습니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/timdeschryver/argument-of-type-interface-is-not-assignable-to-parameter-of-type-interface-2465텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)