我有一个使用immutable包在typescript中编写的react-redux应用程序。我有一个来自api和商店的数据我把它打包到Map。在所有应用程序中,它们都用作Map。
我创建了一个界面:
export interface PaymentMethod extends Immutable.Map<string, string | NamedType<number>> {
id: string;
name: string;
description: string;
accountNr: string;
paymentMethodType: NamedType<number>;
}
一般来说,它的效果非常好。除了测试,我以这种方式创建数据:
const dummyPaymentMethod: PaymentMethod = Map({
id: '',
name: '',
description: '',
accountNr: '',
paymentMethodType: { id: 1, name: '' },
});
然后我得到一个lint错误:
Error:(116, 13) TS2322:Type 'Map<string, string | { id: number; name: string; }>' is not assignable to type 'PaymentMethod'.
Property 'id' is missing in type 'Map<string, string | { id: number; name: string; }>'.
我觉得完全迷失了,因为我可以在界面和虚拟数据中看到id。
我会很感激它。我觉得我应该把可接受的密钥列表传递给我的Map,但不知道怎么做。
编辑:拼错答案 0 :(得分:6)
我们在项目中使用它(略有不同的方法):
interface ImmutableMap<T> extends Map<string, any> {
get<K extends keyof T>(name: K): T[K];
}
我们使用了尚未使用映射类型的Immutable.js
类型的旧版本(T[K]
)。 AFAIK类型从那时起更新,无需覆盖get
方法。
编辑:实际上get
方法仍然不是完全类型安全的,不像上面那样。因此,覆盖该方法仍然有其优点。
通过上述声明,您可以创建不可变的地图,如:
type AuthState = ImmutableMap<{
user:string|null;
loggedIn:boolean;
}>;
const authState:AuthState = fromJS({ user: 'Alice', loggedIn: true });
理想情况下,您希望这样的打字:
/**
* Imaging these are typings for your favorite immutable
* library. We used it to enhance typings of `immutable.js`
* with the latest TypeScript features.
*/
declare function Immutable<T>(o: T): Immutable<T>;
interface Immutable<T> {
get<K extends keyof T>(name: K): T[K];
set<S>(o: S): Immutable<T & S>;
}
const alice = Immutable({ name: 'Alice', age: 29 });
alice.get('name'); // Ok, returns a `string`
alice.get('age'); // Ok, returns a `number`
alice.get('lastName'); // Error: Argument of type '"lastName"' is not assignable to parameter of type '"name" | "age"'.
const aliceSmith = alice.set({ lastName: 'Smith' });
aliceSmith.get('name'); // Ok, returns a `string`
aliceSmith.get('age'); // Ok, returns a `number`
aliceSmith.get('lastName'); // Ok, returns `string`
为了通过Immutable.js
实现上述功能,您可以创建一个小帮助函数,其唯一目的是“修复”类型:
import { fromJS } from 'immutable';
interface Immutable<T> {
get<K extends keyof T>(name: K): T[K];
set<S>(o: S): Immutable<T & S>;
}
function createImmutable<T extends object> (o:T) {
return fromJS(o) as Immutable<T>;
}
请注意,我在示例中使用了fromJS
。只要传递的输入为Map
,这将创建Object
。使用fromJS
优于Map
的好处是,打字更容易被覆盖。
附注:您可能还想查看Record
s。
答案 1 :(得分:0)
留在这里以防它对某人有帮助:
import { Map } from 'immutable';
export interface ImmutableMap<JsObject extends object> extends Omit<Map<keyof JsObject, JsObject>, 'set' | 'get' | 'delete'> {
set: <AKeyOfThatJsObject extends keyof JsObject>(key: AKeyOfThatJsObject, value: ValueOf<Pick<JsObject, AKeyOfThatJsObject>>) => ImmuMap<JsObject>;
get: <AKeyOfThatJsObject extends keyof JsObject>(key: AKeyOfThatJsObject) => ValueOf<Pick<JsObject, AKeyOfThatJsObject>>;
delete: <AKeyOfThatJsObject extends keyof JsObject>(key: AKeyOfThatJsObject, value: ValueOf<Pick<JsObject, AKeyOfThatJsObject>>) => ImmuMap<JsObject>;
}
这对我们来说真的很棒!
我们这样使用它:const aMap: ImmutableMap<OneOfOurObjectTypes>
示例用法:
type BarType = { bar: string };
const foo: BarType = {
bar: 'abc';
};
const immutableBar: Immutable<BarType> = Map(foo);
// immutableBar.get suggests bar as the key, and knows that the result is a string.