解读TypeScript 5.2(二)——— 聊聊装饰器元数据

元数据

首先我们先来看一下元数据的用途有哪些,官网给的用途元数据可能会用于许多用途,例如调试、序列化或使用装饰器执行依赖项注入

看到这里元数据在开发中还是有些应用场景的(ps:在后端依赖注入和序列化还是很有场景的)。

案例分析

这里我们来分析一下官网的第一个案例。

ts 复制代码
interface Context {
    name: string;
    metadata: Record<PropertyKey, unknown>;
}

function setMetadata(_target: any, context: Context) {
    context.metadata[context.name] = true;
}

class SomeClass {
    @setMetadata
    foo = 123;

    @setMetadata
    accessor bar = "hello!";

    @setMetadata
    baz() { }
}
const ourMetadata = SomeClass[Symbol.metadata];
console.log(JSON.stringify(ourMetadata));
// { "bar": true, "baz": true, "foo": true }

首先我们先来分析一下metadata方法,其实我们看TypeScript最新的源代码中Symbol添加了一个新的属性在lib.esnext.decorators文件中。

ts 复制代码
/// <reference no-default-lib="true"/>

/// <reference lib="es2015.symbol" />
/// <reference lib="decorators" />

interface SymbolConstructor {
    readonly metadata: unique symbol;
}

interface Function {
    [Symbol.metadata]: DecoratorMetadata | null;
}

这个属性就是用来存储元数据的。在一个类中我们去调用[Symbol.metadata]方法就可以获取到这个类中的元数据。我们可以在装饰器中去给这个元数据对象(通过源码查看DecoratorMetadata的类型是Record<PropertyKey, unknown> & object)注入数据,例如例子中的这段代码 context.metadata[context.name] = true;。最后我们可以通过类调用[Symbol.metadata]方法获取注入的内容。

应用场景

通过上面的案例我们已经了解元数据应该如何写了,让我们看一下开发中具体的案例来看一下元数据的场景。

ts 复制代码
const serializables = new WeakMap<object, string[]>();
type Context =
    | ClassAccessorDecoratorContext
    | ClassGetterDecoratorContext
    | ClassFieldDecoratorContext
    ;
export function serialize(_target: any, context: Context): void {
    if (context.static || context.private) {
        throw new Error("Can only serialize public instance members.")
    }
    if (typeof context.name !== "string") {
        throw new Error("Can only serialize string properties.");
    }
    let propNames = serializables.get(context.metadata);
    if (propNames === undefined) {
        serializables.set(context.metadata, propNames = []);
    }
    propNames.push(context.name);
}
export function jsonify(instance: object): string {
    const metadata = instance.constructor[Symbol.metadata];
    const propNames = metadata && serializables.get(metadata);
    if (!propNames) {
        throw new Error("No members marked with @serialize.");
    }
    const pairStrings = propNames.map(key => {
        const strKey = JSON.stringify(key);
        const strValue = JSON.stringify((instance as any)[key]);
        return `${strKey}: ${strValue}`;
    });
    return `{ ${pairStrings.join(", ")} }`;
}

class Person {

    firstName: string;

    lastName: string;
    
    @serialize
    age: number

    @serialize
    get fullName() {
        return `${this.firstName} ${this.lastName}`;
    }
    toJSON() {
        return jsonify(this)
    }
    constructor(firstName: string, lastName: string, age: number) {
    }
}

这里是官方给的一个案例,具体的逻辑我就不解释了我想看一遍应该就能看懂,他实现的功能是通过jsonify去打印被serialize装饰器注入的字段。

总结

对于ts新支持的元数据特性我认为主要的应用场景可能是angular或者nodejs(服务端)的场景(ps:现在大趋势是函数式编程)。

相关推荐
To_OC8 小时前
LC 131 分割回文串:刚学回溯时,我连怎么切字符串都想不明白
javascript·算法·leetcode
To_OC9 小时前
LC 42 接雨水:暴力超时卡半天?前后缀数组一用就通了
javascript·算法·leetcode
小林ixn9 小时前
从 ??= 到 onKeyDown:一个 React 组件的“自我修养”
前端·javascript·react.js
এ慕ོ冬℘゜10 小时前
前端实战:jQuery 多条件联合搜索(标题模糊查询 + 日历时间段筛选)
前端·javascript·jquery
随心点儿11 小时前
js postMessage 实现跨域发送消息-应用示例
javascript·ecmascript·postmessage
kyriewen12 小时前
我让AI改一个bug——它偷偷动了5个我没让它碰的地方
前端·javascript·ai编程
gis开发之家17 小时前
《Vue3 从入门到大神35篇》Vue3 源码详解(五):effect 依赖收集原理——track 与 trigger 是如何工作的?
javascript·typescript·前端框架·vue3·vue3源码
橘子星18 小时前
我一个前端切图仔,凭什么能在浏览器里跑大模型?
前端·javascript·前端框架
半个落月18 小时前
用 LangChain JS 做可控写作实验:理解温度参数、提示词与异步调用
javascript·人工智能·后端
观远数据18 小时前
Excel到数据资产池:文件数据入湖的治理规范怎么建
前端·javascript·excel