微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何根据以前的值进行打字稿定义?

如何解决如何根据以前的值进行打字稿定义?

例如,请参见以下代码

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

Playground Link

,

实际上有可能! 排序。我们可以使用控制流类型缩小(感谢@ kaya3)以及泛型类型(T)来跟踪已设置的键。但是,由于类型 narrowing 只能添加键,而不能将其删除。

这是一个使用setget的示例地图:
(如果您不想使用单独的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.

Playground Link

key: string extends K ? never : K是一种骇客程序,可防止您向地图提供非特定的string,这会终止键跟踪。


使用写时复制的旧示例:

Playground Link

,

要实现此目的,您需要构造所需的对象类型。以下代码允许您执行此操作。

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 举报,一经查实,本站将立刻删除。