Tôi có một thư viện xuất một loại tiện ích tương tự như sau:
type Action<Model extends object> = (data: State<Model>) => State<Model>;
Loại tiện ích này cho phép bạn khai báo một chức năng sẽ thực hiện dưới dạng "hành động". Nó nhận được một đối số chung là Model
hành động sẽ chống lại.
Đối data
số của "hành động" sau đó được gõ với một loại tiện ích khác mà tôi xuất;
type State<Model extends object> = Omit<Model, KeysOfType<Model, Action<any>>>;
Các State
loại tiện ích cơ bản mất đến Model
chung chung và sau đó tạo ra một loại mới, nơi tất cả các tính năng mà các loại Action
đã được gỡ bỏ.
Ví dụ ở đây là một người sử dụng đất cơ bản thực hiện các điều trên;
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;
}
}
Ở trên đang làm việc rất tốt. 👍
Tuy nhiên, có một trường hợp mà tôi đang vật lộn, cụ thể là khi định nghĩa mô hình chung được xác định, cùng với hàm xuất xưởng để tạo ra các thể hiện của mô hình chung.
Ví dụ;
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;
}
};
}
Trong ví dụ trên, tôi hy vọng data
đối số sẽ được nhập vào nơi doSomething
hành động đã bị xóa và thuộc tính chung value
vẫn tồn tại. Tuy nhiên đây không phải là trường hợp - value
tài sản cũng đã bị xóa bởi State
tiện ích của chúng tôi .
Tôi tin rằng nguyên nhân cho điều này là T
chung chung mà không có bất kỳ hạn chế / thu hẹp nào được áp dụng cho nó, và do đó hệ thống loại quyết định rằng nó giao với một Action
loại và sau đó loại bỏ nó khỏi data
loại đối số.
Có cách nào để khắc phục hạn chế này không? Tôi đã làm một số nghiên cứu và đã hy vọng sẽ có một số cơ chế, trong đó tôi có thể nói rằng T
bất kỳ ngoại trừ cho một Action
. tức là hạn chế loại âm.
Hãy tưởng tượng:
function modelFactory<T extends any except Action<any>>(value: T): UserDefinedModel<T> {
Nhưng tính năng đó không tồn tại cho TypeScript.
Có ai biết một cách tôi có thể làm cho nó hoạt động như tôi mong đợi không?
Để hỗ trợ gỡ lỗi ở đây là một đoạn mã đầy đủ:
// 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;
}
};
}
Bạn có thể chơi với ví dụ mã này tại đây: https://codesandbox.io/s/reverent-star-m4sdb?fontsize=14