다음과 유사한 유틸리티 유형을 내보내는 라이브러리가 있습니다.
type Action<Model extends object> = (data: State<Model>) => State<Model>;
이 유틸리티 유형을 사용하면 "조치"로 수행 할 함수를 선언 할 수 있습니다. Model조치가 수행 될 것이라는 일반적인 인수를받습니다 .
그만큼 data그런 다음 "액션" 인수는 내가 내보내는 다른 유틸리티 유형으로 입력됩니다.
type State<Model extends object> = Omit<Model, KeysOfType<Model, Action<any>>>;
그만큼 State유틸리티 유형은 기본적으로 수신한다 Model일반을 다음 유형의 모든 속성이 새로운 유형의 생성 Action제거 된합니다.
예를 들어 여기에 위의 기본 사용자 토지 구현이 있습니다.
interface MyModel {
counter: number;
increment: Action<Model>;
}
const myModel = {
counter: 0,
increment: (data) => {
data.counter; // Exists and typed as `number`
data.increment; // Does not exist, as stripped off by State utility
return data;
}
}
위의 내용은 매우 잘 작동합니다. 👍
그러나 제네릭 모델의 인스턴스를 생성하는 팩토리 함수와 함께 제네릭 모델 정의가 정의 된 경우 특히 어려움을 겪고있는 경우가 있습니다.
예를 들어;
interface MyModel<T> {
value: T; // 👈 a generic property
doSomething: Action<MyModel<T>>;
}
function modelFactory<T>(value: T): MyModel<T> {
return {
value,
doSomething: data => {
data.value; // Does not exist 😭
data.doSomething; // Does not exist 👍
return data;
}
};
}
위의 예제 data에서 doSomething액션이 제거 된 위치에 인수가 입력 될 것으로 예상 하고 일반 value속성이 여전히 존재합니다. 그러나 이것은 사실이 아닙니다- value재산이 우리 State유틸리티에 의해 제거되었습니다 .
나는 이것의 원인이 T유형 제한 / 축소가 적용되지 않은 일반적인 것이라고 생각하기 때문에 유형 시스템은 Action유형과 교차한다고 결정한 다음 data인수 유형 에서 제거합니다 .
이 제한을 극복 할 수있는 방법이 있습니까? 나는 몇 가지 조사를 수행하고 난 그 상태 할 수있는 몇 가지 메커니즘이 될 것 기대했다 T어떤이다 제외 에 대한 Action. 즉 네거티브 타입 제한.
상상해보십시오.
function modelFactory<T extends any except Action<any>>(value: T): UserDefinedModel<T> {
그러나 TypeScript에는 해당 기능이 없습니다.
누구든지 내가 예상대로 작동하도록 할 수있는 방법을 알고 있습니까?
디버깅을 돕기 위해 전체 코드 스 니펫이 있습니다.
// Returns the keys of an object that match the given type(s)
type KeysOfType<A extends object, B> = {
[K in keyof A]-?: A[K] extends B ? K : never
}[keyof A];
// Filters out an object, removing any key/values that are of Action<any> type
type State<Model extends object> = Omit<Model, KeysOfType<Model, Action<any>>>;
// My utility function.
type Action<Model extends object> = (data: State<Model>) => State<Model>;
interface MyModel<T> {
value: T; // 👈 a generic property
doSomething: Action<MyModel<T>>;
}
function modelFactory<T>(value: T): MyModel<T> {
return {
value,
doSomething: data => {
data.value; // Does not exist 😭
data.doSomething; // Does not exist 👍
return data;
}
};
}
https://codesandbox.io/s/reverent-star-m4sdb?fontsize=14 에서이 코드 예제를 사용할 수 있습니다.