TypeScript

从 v3 开始,Socket.IO 现在对TypeScript具有很好的支持。

服务器

首先,声明一些类型:

  1. interface ServerToClientEvents {
  2. noArg: () => void;
  3. basicEmit: (a: number, b: string, c: Buffer) => void;
  4. withAck: (d: string, callback: (e: number) => void) => void;
  5. }
  6. interface ClientToServerEvents {
  7. hello: () => void;
  8. }
  9. interface InterServerEvents {
  10. ping: () => void;
  11. }
  12. interface SocketData {
  13. name: string;
  14. age: number;
  15. }

并在创建服务器时使用它们:

  1. const io = new Server<
  2. ClientToServerEvents,
  3. ServerToClientEvents,
  4. InterServerEvents,
  5. SocketData
  6. >();

然后,从 IDE 的帮助中获益!

ServerToClientEvents在发送和广播事件时使用接口中声明的事件:

  1. io.on("connection", (socket) => {
  2. socket.emit("noArg");
  3. socket.emit("basicEmit", 1, "2", Buffer.from([3]));
  4. socket.emit("withAck", "4", (e) => {
  5. // e is inferred as number
  6. });
  7. // works when broadcast to all
  8. io.emit("noArg");
  9. // works when broadcasting to a room
  10. io.to("room1").emit("basicEmit", 1, "2", Buffer.from([3]));
  11. });

ClientToServerEvents接收事件时使用接口中声明的那些:

  1. io.on("connection", (socket) => {
  2. socket.on("hello", () => {
  3. // ...
  4. });
  5. });

接口中声明的InterServerEvents用于服务器间通信(于socket.io@4.1.0添加):

  1. io.serverSideEmit("ping");
  2. io.on("ping", () => {
  3. // ...
  4. });

最后,SocketData type 用于键入 socket.data 属性 (于socket.io@4.4.0添加):

  1. io.on("connection", (socket) => {
  2. socket.data.name = "john";
  3. socket.data.age = 42;
  4. });

TypeScript - 图1警告

这些类型提示不会取代输入的正确验证/清理。像往常一样,永远不要相信用户输入。

客户端

在客户端,您可以重用相同的ServerToClientEventsClientToServerEvents 接口:

  1. import { io, Socket } from "socket.io-client";
  2. // please note that the types are reversed
  3. const socket: Socket<ServerToClientEvents, ClientToServerEvents> = io();

同样,在ClientToServerEvents发送事件时使用接口中声明的事件:

  1. socket.emit("hello");

ServerToClientEvents并且在接收事件时使用声明的那些:

  1. socket.on("noArg", () => {
  2. // ...
  3. });
  4. socket.on("basicEmit", (a, b, c) => {
  5. // a is inferred as number, b as string and c as buffer
  6. });
  7. socket.on("withAck", (d, callback) => {
  8. // d is inferred as string and callback as a function that takes a number as argument
  9. });

Custom types for each namespace

Since each Namespace can have its own set of events, you can also provide some types for each one of them:

  1. import { Server } from "socket.io";
  2. // types for the main namespace
  3. const io = new Server<ClientToServerEvents, ServerToClientEvents, InterServerEvents, SocketData>();
  4. // types for the namespace named "/my-namespace"
  5. interface NamespaceSpecificClientToServerEvents {
  6. foo: (arg: string) => void
  7. }
  8. interface NamespaceSpecificServerToClientEvents {
  9. bar: (arg: string) => void;
  10. }
  11. interface NamespaceSpecificInterServerEvents {
  12. // ...
  13. }
  14. interface NamespaceSpecificSocketData {
  15. // ...
  16. }
  17. const myNamespace: Namespace<
  18. NamespaceSpecificClientToServerEvents,
  19. NamespaceSpecificServerToClientEvents,
  20. NamespaceSpecificInterServerEvents,
  21. NamespaceSpecificSocketData
  22. > = io.of("/my-namespace");
  23. myNamespace.on("connection", (socket) => {
  24. socket.on("foo", () => {
  25. // ...
  26. });
  27. socket.emit("bar", "123");
  28. });

And on the client side:

  1. import { io, Socket } from "socket.io-client";
  2. const socket: Socket<
  3. NamespaceSpecificServerToClientEvents,
  4. NamespaceSpecificClientToServerEvents
  5. > = io("/my-namespace");
  6. socket.on("bar", (arg) => {
  7. console.log(arg); // "123"
  8. });