如何为我的 JavaScript 模块添加类型?

How do I add typings for my JavaScript module?

提问人:Ruri 提问时间:11/16/2023 最后编辑:Ruri 更新时间:11/16/2023 访问量:42

问:

这绝对是重复的,但我很难弄清楚如何将d.ts等类型添加到我的库/模块中。

我尝试编辑我的并添加,但它似乎不起作用,所以也许我只是做错了。package.json"types": "./typings/index.d.ts"

它还使用一个旧库,我将其用作 API,而这个模块只是它的客户端包装器。

引用:

// index.d.ts

export class Message {
    constructor(client: any, message: any)
    attachments: any[];
    body: string;
    isGroup: boolean;
    mentions: { [id: string]: string };
    messageID: string;
    senderID: string;
    threadID: string;
    isUnread: boolean;
    type: 'message';
}
// Message.js

class Message {
    constructor(_client, event) {
        for (const key in event) {
            if (event.hasOwnProperty(key)) {
                this[key] = event[key];
            }
        }
    }
}

module.exports = Message;
// MessageCreate.js (Event handler)

const Message = require('../../structures/Message');

module.exports = (client, event) => {
    const message = new Message(client, event);
    client.emit('messageCreate', message);
}
// index.js (main script)

const MessengerClient = require("./src/client/Client");

const appState = require('./appState.json');
const client = new MessengerClient();

client.on('ready', (client) => {
    console.log(`Logged in as '${client.user.name}'`);
})

client.on('messageCreate', (message) => { // Here, I want to add a type for message
    console.log(message);
})

client.login(appState);
// Client.js

const login = require("../lib/index");
const { EventEmitter } = require('events');
const Events = require('./Event.js');

class MessengerClient extends EventEmitter {
    constructor(options = {}) {
        super();
        this.api = null;
        this.options = options;
        this.user = null;
    }
    
    async login(appState) {
        try {
            const api = await new Promise((resolve, reject) => {
                login(appState, (err, api) => {
                    if (err) {
                        reject(err);
                    } else {
                        resolve(api);
                    }
                });
            });
            
            this.api = api;
            const clientID = api.getCurrentUserID();
            const clientUser = await api.getUserInfo(clientID);
            this.user = clientUser[clientID];
            new Events(this);
            
        } catch (error) {
            console.error('Error during login:', error);
        }
    }
}

module.exports = MessengerClient;
JavaScript TypeScript 类型

评论

0赞 Jared Smith 11/16/2023
您需要为 MessengerClient.prototype.on 添加重载签名,但您还没有键入该类......或在您发布的代码中向我们展示。
1赞 Ruri 11/16/2023
@JaredSmith我编辑了我的问题,你能再检查一次吗?
0赞 Jared Smith 11/16/2023
好多了,发布了答案。

答:

0赞 Jared Smith 11/16/2023 #1

您需要为 MessageClient 类编写声明,并为该方法添加重载签名。我通常只写打字稿,而不是手动写声明文件,但它应该看起来像这样:on

export class MessageClient {
    api: null | whatever; // replace with real type
    options: null | whatever; // replace with real type
    user: null | whatever; // replace with real type

    login(state: whatever): Promise<void>; // replace with real type
    
    on(evtType: 'messageCreate', cb: (msg: Message) => void): void
    on(evtType: string, cb: (result?: any) => void): void // you may want unknown here instead of any
}

请注意,重载通常应从上到下更具体到更不具体。

我不得不这样说:我意识到你可能没有责任,你可能无法改变它,但代码设计得很糟糕。如果类在构造时具有一堆 null 属性,这些属性在将来的某个时间点被初始化,则是一种 OO 反模式

如果此类需要登录信息才能正确实例化,则不应是该类的方法。将它拉出到函数中,并在拥有它后才实例化 MessengerClient,然后删除所有 s。login| null

使用构造函数来产生副作用(例如没有分配给任何东西)也是另一种 OO 反模式。没有看到足够的代码来为您提供不同的建议,但这是一个很常见的问题,Javascript linter 有禁止这样做的规则(您在这个项目中使用了 linter......对吧?new Events(this);

评论

0赞 Ruri 11/16/2023
这样做了,它仍然不起作用(每当我将鼠标悬停在消息上时,它仍然any)
0赞 Jared Smith 11/16/2023
@Ruri 1.只有当事件类型是编译时常量(如字符串文本)时,它才会起作用(并且只能起作用)。2. 你是怎么检查的?这应该有效,所以我会通过将 (result?: any) 更改为 (result: number) 来测试测试,并查看 IDE 中的工具提示是否更改。