如何解决如何根据以前的值进行打字稿定义?
例如,请参见以下代码:
var a
a.set('my-custom-value',55)
a.
在第3行中,如何让IDE知道第2行中的值,并为使用库的最终用户定义的字符串提供自动完成功能?
我希望在输入a.
之后,我将看到VSCode将“我的自定义值”作为自动完成选项。
我看到yargs
像那样工作。如果我定义了一个选项或一个位置参数,那么以后IDE会提供我选择的内容。
解决方法
这可以通过asserts
return type完成,这是可能的,因为Typescript支持缩小控制流类型:
class Foo {
setKey<K extends PropertyKey,V>(k: K,v: V): asserts this is Record<K,V> {
(this as any)[k] = v;
}
}
let foo: Foo = new Foo();
// foo. completes as foo.setKey
foo.setKey('bar',23);
// now foo. completes as foo.bar or foo.setKey
,
实际上有可能! 排序。我们可以使用控制流类型缩小(感谢@ kaya3)以及泛型类型(T
)来跟踪已设置的键。但是,由于类型 narrowing 只能添加键,而不能将其删除。
这是一个使用set
和get
的示例地图:
(如果您不想使用单独的get
函数,请参见@ kaya3的答案以获取更简单的示例)
// Tracking map.
class TMap<V,T extends Record<string,V> = {}> {
public static create<V>(): TMap<V> {
return new TMap({});
}
private _data: T;
private constructor(data: T) {
this._data = data;
}
public set<K extends string>(key: string extends K ? never : K,val: V): asserts this is TMap<V,Record<K,V> & T> {
(this._data as Record<K,V>)[key] = val;
}
public get<K extends keyof T>(key: K): V {
return this._data[key];
}
}
const a: TMap<number> = TMap.create();
a.set('my-custom-value',55);
// a.get tooltip: get(key: "my-custom-value"): number
a.set('my-other-key',22);
a.set('my-other-key',33);
// a.get tooltip: get(key: "my-custom-value" | "my-other-key"): number
const x = a.get('my-custom-value');
const y = a.get('my-other-key');
const unknownString: string = 'mystery-key';
// a.set(unknownString,101); // Not allowed b/c we don't know the exact string value.
key: string extends K ? never : K
是一种骇客程序,可防止您向地图提供非特定的string
,这会终止键跟踪。
使用写时复制的旧示例:
,要实现此目的,您需要构造所需的对象类型。以下代码允许您执行此操作。
class Builder<T extends object = {}> {
private _obj: any
constructor(t: T) {
this._obj = { ...t }
Object.keys(t).forEach((key) => (this as any)[key] = (t as any)[key])
}
public set<K extends string,V>(key: K,value: V): Builder<SetResult<T,K,V>> & SetResult<T,V> {
(this._obj)[key] = value
return new Builder<SetResult<T,V>>(this._obj) as Builder<SetResult<T,V>
}
}
type SetResult<T,K extends string,V> = T & { [k in K]: V }
以这种方式使用代码:
const a = new Builder({})
.set('abc',55)
.set('def','name')
.set('my_complex_variable',{ ID: '1234',exists: false })
console.log(a.abc)
console.log(a.def)
console.log(a.my_complex_variable.ID)
它的工作方式非常简单。每次对set
函数的调用都会返回一个新的Builder
对象,其中包含所有先前的set
调用。请注意,您访问的每个字段也是强类型的:abc
是数字,def
是字符串。对any
类型的转换有些讨厌,但是如果需要,您可以清理掉
这里是working code
的链接编辑:我刚刚注意到,如果您使用带连字符的变量名,则如果您使用.
,Intellisense不会将其作为建议。您仍然可以在字段上进行类型检查,但是必须使用索引器进行访问:
const a = new Builder({}).set('my-variable',12)
console.log(a['my-variable'])
,
如果您知道将要设置的值,则可以尝试类似的操作
let a: { value?: number } = {}
a.value = 55
但是值将始终为number | undefined
类型,因为打字稿编译器不知道您是否在代码的任何位置设置了值。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。