Saya memiliki perpustakaan yang mengekspor jenis utilitas yang mirip dengan yang berikut:
type Action<Model extends object> = (data: State<Model>) => State<Model>;
Jenis utilitas ini memungkinkan Anda untuk mendeklarasikan fungsi yang akan berfungsi sebagai "tindakan". Ia menerima argumen umum Model
bahwa tindakan itu akan dilawan.
The data
Argumen dari "tindakan" kemudian diketik dengan jenis utilitas lain yang saya ekspor;
type State<Model extends object> = Omit<Model, KeysOfType<Model, Action<any>>>;
The State
utilitas jenis pada dasarnya mengambil masuk Model
generik dan kemudian menciptakan jenis baru di mana semua properti yang bertipe Action
telah dihapus.
Untuk misalnya di sini adalah implementasi dasar pengguna lahan di atas;
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;
}
}
Di atas bekerja dengan sangat baik. 👍
Namun, ada kasus yang saya perjuangkan, khususnya ketika definisi model generik didefinisikan, bersama dengan fungsi pabrik untuk menghasilkan contoh-contoh model generik.
Sebagai contoh;
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;
}
};
}
Pada contoh di atas saya berharap data
argumen akan diketik di mana doSomething
tindakan telah dihapus, dan value
properti generik masih ada. Namun ini tidak terjadi - value
properti juga telah dihapus oleh State
utilitas kami .
Saya percaya penyebabnya T
adalah generik tanpa batasan jenis / penyempitan yang diterapkan padanya, dan karena itu sistem tipe memutuskan bahwa ia bersinggungan dengan suatu Action
tipe dan kemudian menghapusnya dari data
tipe argumen.
Apakah ada cara untuk mengatasi batasan ini? Saya telah melakukan beberapa penelitian dan berharap akan ada beberapa mekanisme di mana saya dapat menyatakan bahwa T
ada kecuali untuk Action
. yaitu pembatasan tipe negatif.
Membayangkan:
function modelFactory<T extends any except Action<any>>(value: T): UserDefinedModel<T> {
Tetapi fitur itu tidak ada untuk TypeScript.
Apakah ada yang tahu cara saya bisa membuat ini berfungsi seperti yang saya harapkan?
Untuk membantu debugging di sini adalah cuplikan kode lengkap:
// 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;
}
};
}
Anda dapat bermain dengan contoh kode ini di sini: https://codesandbox.io/s/reverent-star-m4sdb?fontsize=14
sumber
Persis seperti yang Anda katakan, masalahnya adalah kita belum memiliki kendala negatif. Saya juga berharap mereka bisa mendapatkan fitur seperti itu segera. Sambil menunggu, saya mengusulkan solusi seperti ini:
sumber
count
danvalue
akan selalu membuat compiler tidak senang. Untuk memperbaikinya Anda dapat mencoba sesuatu seperti ini:Karena
Partial
tipe utilitas sedang digunakan, Anda akan baik-baik saja jikatransform
metode case tidak ada.Stackblitz
sumber
Secara umum saya membaca itu dua kali dan tidak sepenuhnya mengerti apa yang ingin Anda capai. Dari pemahaman saya, Anda ingin menghilangkan
transform
dari jenis yang diberikan dengan tepattransform
. Untuk mencapai itu sederhana, kita perlu menggunakan Abaikan :Tidak yakin apakah ini yang Anda inginkan karena kompleksitas yang Anda berikan pada tipe utilitas tambahan. Semoga ini bisa membantu.
sumber