TypeScript でキー/バリューを与えたら、get(キー) のキーで補完が効く&TSチェック入る、というクラスの作り方。具体的には、下記のようなことが可能なクラスをの作成方法。
const a = new CompletionMap({
aa: 1,
bb: 2,
})
// 補完が効いて、'aa', 'bb' が選択可能になる
a.get('aa')
a.get('bb')
// 値の書き換えも可能
a.put('bb', 22)
// 未知のキーはTS的に怒られる
a.get('cc')
a.put('cc', 3)
// キー/バリューを加えることもできる
const b = a.mergeValues({ cc: 3 })
// 補完が効いて、'aa', 'bb', 'cc' が選択可能になる
b.get('aa')
b.get('bb')
b.get('cc')
// これは怒られる
b.get('dd')
方法:
export declare type CMValue = any
export declare type CMKeyValues = { [key: string]: CMValue }
class CompletionMap<T extends CMKeyValues> {
constructor (
public _data: T = {} as T
) {
}
get (key: keyof T): CMValue {
return this._data[key]
}
put (key: keyof T, value: CMValue) {
this._data[key] = value
}
/**
* 引数で追加のオブジェクトを受け取って、マージしたオブジェクトを返す
*/
mergeValues<T2 extends CMKeyValues> (additions: T2): CompletionMap<T & T2> {
return new CompletionMap<T & T2>({ ...this._data, ...additions })
}
/**
* 引数でインスタンスを受け取る場合
*/
static mergeInstance<U extends CompletionMap<CMValue>, T2 extends CMKeyValues> (
instance: U,
additions: T2
): CompletionMap<U['_data'] & T2> {
return new CompletionMap<U['_data'] & T2>({ ...instance._data, ...additions })
}
}
test('test', () => {
const a = new CompletionMap({
aa: 1,
bb: 2,
})
expect(a.get('aa')).toBe(1)
expect(a.get('bb')).toBe(2)
// expect(a.get('cc')).toBe(3)
a.put('bb', 22)
expect(a.get('bb')).toBe(22)
const b = a.mergeValues({ dd: 4 })
expect(b.get('aa')).toBe(1)
expect(b.get('bb')).toBe(22)
// expect(b.get('cc')).toBe(3)
expect(b.get('dd')).toBe(4)
const c = new CompletionMap({
...a._data,
cc: 3,
})
expect(c.get('aa')).toBe(1)
expect(c.get('bb')).toBe(22)
expect(c.get('cc')).toBe(3)
// expect(c.get('dd')).toBe(4)
const d = CompletionMap.mergeInstance(a, { dd: 4 })
expect(d.get('aa')).toBe(1)
expect(d.get('bb')).toBe(22)
// expect(d.get('cc')).toBe(3)
expect(d.get('dd')).toBe(4)
})