TypeScript Add typed return for Object.defineProperties

gywdnpxw  于 6个月前  发布在  TypeScript
关注(0)|答案(5)|浏览(56)

搜索词

Object.definePropertiestyped

建议

const newObject = Object.defineProperties(o, map);

用例

在仍然能够对它们进行类型检查的情况下创建某些属性的扩展。

示例

/** @type {NodeList} */
const nodeListObject = Object.defineProperties(/** @type {Node[]} */ ([]), {
    item: {
      enumerable: false,
      /** @param {number} [index] */
      value: function item(index) { return this[index]; },
    },
  });

检查清单

我的建议满足以下准则:

  • 这不会对现有的TypeScript/JavaScript代码造成破坏性更改
  • 这不会改变现有JavaScript代码的运行时行为
  • 这可以在不根据表达式的类型发出不同的JS的情况下实现
  • 这不是一个运行时特性(例如库功能、带有JavaScript输出的非ECMAScript语法等)
  • 这个特性将与 TypeScript's Design Goals 的其他部分保持一致。

我目前使用的类型是以下:

interface ObjectConstructor {
  defineProperties<T1, T2 = PropertyDescriptorMap>(o: T1, properties: T2 & ThisType<T1>): T1 & {
        [K in keyof T2]: (
          T2[K]['get'] extends Function ? ReturnType<T2[K]['get']> :
          T2[K]['set'] extends Function ? Parameters<T2[K]['set']>[0] :
          T2[K]['value'] extends undefined ? any : T2[K]['value']
        )
      };
}

看起来还不错,但我很想得到一些反馈。目前,我的目标是针对 .get() ,然后是 .set(arg0) ,最后是 .value
参见: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties

hmmo2u0o

hmmo2u0o1#

你的代码无法正确处理非writable属性,而我的代码更加准确:

interface ObjectConstructor {
	defineProperty<
		T,
		P extends PropertyKey,
		V = P extends keyof T ? T[P] : unknown,
		W = P extends keyof T ? true : false
	>(
		target: T,
		property: P,
		descriptor: TypedPropertyDescriptor<V> & { readonly writable?: W },
	): (T &
		{ readonly [K in P as W extends false ? K : never]: V } &
		{ -readonly [K in P as W extends true ? K : never]: V })
		// Needs https://github.com/microsoft/TypeScript/issues/40562:
		// & (asserts target is T &
		//	{ readonly [K in P as W extends false ? K : never]: V } &
		//	{ -readonly [K in P as W extends true ? K : never]: V });

	defineProperties<
		T,
		M extends Record<string | symbol, PropertyDescriptor>
	>(
		target: T,
		properties: M & ThisType<T>,
	): ({} extends M ? T : T & {
			readonly [K in keyof M as M[K] extends { readonly writable: false } ? K : (K extends keyof T ? never : K)]:
				M[K] extends Readonly<TypedPropertyDescriptor<infer V>> ? V : any;
		} & {
			-readonly [K in keyof M as M[K] extends { readonly writable: true } ? K : (K extends keyof T ? K : never)]:
				M[K] extends Readonly<TypedPropertyDescriptor<infer V>> ? V : any;
		})
		// Needs https://github.com/microsoft/TypeScript/issues/40562:
		// & (asserts target is ({} extends M ? T : T & {
		//	readonly [K in keyof M as M[K] extends { readonly writable: false } ? K : (K extends keyof T ? never : K)]:
		//		M[K] extends Readonly<TypedPropertyDescriptor<infer V>> ? V : any;
		// } & {
		//	-readonly [K in keyof M as M[K] extends { readonly writable: true } ? K : (K extends keyof T ? K : never)]:
		//		M[K] extends Readonly<TypedPropertyDescriptor<infer V>> ? V : any;
		// }))
}
0yg35tkg

0yg35tkg2#

啊,我没有看到 TypedPropertyDescriptor ,这会让事情变得容易得多。为什么这个不是输入法的一部分?

6jjcrrmo

6jjcrrmo3#

这可能是为了兼容旧版本。
这可能也是为什么strictBindCallApply不是默认选项的原因。

mlnl4t2r

mlnl4t2r4#

PR #42424 似乎是一个解决这个问题的开始。

cqoc49vn

cqoc49vn5#

@ExE-Boss 您的定义似乎更有用。也许将其转变为PR是有意义的?#40562是否必不可少?
在CoffeeScript中添加适当的Object.defineProperties定义是处理getter/setter的一种方法,因为它目前没有内置支持,所以推荐使用defineProperty。在this discussion中提到了TypeScript的支持不足。

相关问题