在插件开发中遇到问题-某类型上不存在某属性及该属性不在类型中等

import { Context, Schema, h } from 'koishi'

export const name = 'minecraft-fishing'

export const inject = ['database']

export interface Config {}

export const Config: Schema<Config> = Schema.object({})

export interface User {
  id: number
  exp: number
  items: Record<string, number>
}

export function apply(ctx: Context) {
  ctx.model.extend('user', {
    exp: 'integer',
    items: 'json',
  })

  ctx.command("mc.钓鱼", "随便钓点什么上来")
    .action(async ({ session }) => {
      const userId = parseInt(session.userId);
      if (!(userId)) {
        return session.send('无法获取用户ID');
      }

      const items = [
        { item: 'fish', weight: 85 },
        { item: 'rubbish', weight: 10 },
        { item: 'baozang', weight: 5 },
      ];

      function weightedRandom(items) {
        const totalWeight = items.reduce((sum, item) => sum + item.weight, 0);
        let random = Math.random() * totalWeight;
        for (const item of items) {
          if (random < item.weight) {
            return item.item;
          }
          random -= item.weight;
        }
        return items[0].item;
      }

      const result = weightedRandom(items);

      let selection;
      let aliases;

      if(result === "fish"){
        const fish = [
          { item: "shengxueyu", alias: "生鳕鱼", weight: 65, url: "https://i.postimg.cc/WbBfndvb/shengxueyu.webp" },
          { item: "shengguiyu", alias: "生鲑鱼", weight: 25, url: "https://i.postimg.cc/yNBQM2xM/shengguiyu.png" },
          { item: "hetun", alias: "河豚", weight: 13, url: "https://i.postimg.cc/V6hFkhsL/hetun.webp" },
          { item: "redaiyu", alias: "热带鱼", weight: 2, url: "https://i.postimg.cc/5t37bpF6/redaiyu.png" }
        ];
        selection = weightedRandom(fish);
        aliases = fish;
      } else if(result === "rubbish"){
        const rubbish = [
          { item: "shuilian", alias: "睡莲", weight: 17, url: "https://i.postimg.cc/qRvmRn8Q/shuilian.png" },
          { item: "wan", alias: "碗", weight: 10, url: "https://i.postimg.cc/4d2WhdPG/wan.webp" },
          { item: "diaoyugan", alias: "钓鱼竿", weight: 2, url: "https://i.postimg.cc/Vk94W4gD/diaogan.webp" },
          { item: "pige", alias: "皮革", weight: 10, url: "https://i.postimg.cc/9Xvvx8Ph/pige.webp" },
          { item: "pigexuezi", alias: "皮革靴子", weight: 10, url: "https://i.postimg.cc/13D7Yym0/pigexuezi.webp" },
          { item: "furou", alias: "腐肉", weight: 10, url: "https://i.postimg.cc/g0YsSRBd/furou.webp" },
          { item: "mugun", alias: "木棍", weight: 5, url: "https://i.postimg.cc/c1KpBynh/mugun.webp" },
          { item: "shuiping", alias: "水瓶", weight: 10, url: "https://i.postimg.cc/rsvgQP7Y/yaoshui.webp" },
          { item: "gutou", alias: "骨头", weight: 10, url: "https://i.postimg.cc/C15NY0gQ/gutou.webp" },
          { item: "monang", alias: "墨囊", weight: 1, url: "https://i.postimg.cc/fknjx00G/mo-nang.webp" },
          { item: "banxiangou", alias: "绊线钩", weight: 10, url: "https://i.postimg.cc/2SN2WgQ1/banxiangou.webp" }
        ];
        selection = weightedRandom(rubbish);
        aliases = rubbish;
      } else {
        const baozang = [
          { item: "gong", alias: "弓", weight: 17, url: "https://i.postimg.cc/wB0VSvSN/gong.webp" },
          { item: "fumoshu", alias: "附魔书", weight: 16, url: "https://i.postimg.cc/WbgxxGSJ/fumoshu.gif" },
          { item: "diaoyugan", alias: "钓鱼竿", weight: 17, url: "https://i.postimg.cc/Vk94W4gD/diaogan.webp" },
          { item: "mingmingpai", alias: "命名牌", weight: 16, url: "https://i.postimg.cc/4yhQ71nv/mingmingpai.webp" },
          { item: "yingwuluoke", alias: "鹦鹉螺壳", weight: 17, url: "https://i.postimg.cc/dQXWshDm/yingwuluoke.webp" },
          { item: "an", alias: "鞍", weight: 17, url: "https://i.postimg.cc/MKQ9vzQk/an.webp" }
        ];
        selection = weightedRandom(baozang);
        aliases = baozang;
      }

      const selectedItem = aliases.find(item => item.item === selection);
      const expGain = Math.floor(Math.random() * 6) + 1;
      let user = await ctx.database.get('user', { id: userId });
      if (!user.length) {
        user = [{
          id: userId,
          exp: 0,
          items: {}
        }];
      }
      const updateData = {
        exp: user[0].exp + expGain,
        items: {
          ...user[0].items,
          [selectedItem.item]: (user[0].items[selectedItem.item] || 0) + 1
        }
      } as User;

      await ctx.database.upsert('user', [{ id: userId, ...updateData }]);

      return session.send(`你钓到了: ${selectedItem.alias} ,\n ${h.image(selectedItem.url)} 并获得了 ${expGain} 点经验!`);
    });
}

问过GPT使用了扩展模型和类型断言但还是报错
错误:
类型“User”上不存在属性“exp”。ts(2339)
类型“User”上不存在属性“items”。ts(2339)
对象字面量只能指定已知属性,并且“exp”不在类型“User”中。
对象字面量只能指定已知属性,并且“exp”不在类型“MapField<{ id: number; } & { name: string; } & { flag: number; } & { authority: number; } & { locales: string; } & { permissions: string; } & { createdAt: Date; }, Types>”中。ts(2353)

1 个赞

类型没声明好

1 个赞
import { Context, Schema, User, h } from 'koishi'

export const name = 'minecraft-fishing'

export const inject = ['database']

export interface Config {}

declare module 'koishi' {
  interface User {
    id: number
    exp: number
    items: Record<string, number>
  }
}

export const Config: Schema<Config> = Schema.object({})

export function apply(ctx: Context) {
  ctx.model.extend('user', {
    exp: 'integer',
    items: 'json',
  })

  ctx.command("mc-钓鱼", "随便钓点什么上来")
    .action(async ({ session }) => {
      const userId = parseInt(session.userId); 
      if (isNaN(userId)) {
        return session.send('无法获取用户ID');
      }

      const items = [
        { item: 'fish', weight: 85 },
        { item: 'rubbish', weight: 10 },
        { item: 'baozang', weight: 5 },
      ];

      function weightedRandom(items) {
        const totalWeight = items.reduce((sum, item) => sum + item.weight, 0);
        let random = Math.random() * totalWeight;
        for (const item of items) {
          if (random < item.weight) {
            return item.item;
          }
          random -= item.weight;
        }
        return items[0].item;
      }

      const result = weightedRandom(items);

      let selection;
      let aliases;

      if(result === "fish"){
        const fish = [
          { item: "shengxueyu", alias: "生鳕鱼", weight: 65, url: "https://i.postimg.cc/WbBfndvb/shengxueyu.webp" },
          { item: "shengguiyu", alias: "生鲑鱼", weight: 25, url: "https://i.postimg.cc/yNBQM2xM/shengguiyu.png" },
          { item: "hetun", alias: "河豚", weight: 13, url: "https://i.postimg.cc/V6hFkhsL/hetun.webp" },
          { item: "redaiyu", alias: "热带鱼", weight: 2, url: "https://i.postimg.cc/5t37bpF6/redaiyu.png" }
        ];
        selection = weightedRandom(fish);
        aliases = fish;
      } else if(result === "rubbish"){
        const rubbish = [
          { item: "shuilian", alias: "睡莲", weight: 17, url: "https://i.postimg.cc/qRvmRn8Q/shuilian.png" },
          { item: "wan", alias: "碗", weight: 10, url: "https://i.postimg.cc/4d2WhdPG/wan.webp" },
          { item: "diaoyugan", alias: "钓鱼竿", weight: 2, url: "https://i.postimg.cc/Vk94W4gD/diaogan.webp" },
          { item: "pige", alias: "皮革", weight: 10, url: "https://i.postimg.cc/9Xvvx8Ph/pige.webp" },
          { item: "pigexuezi", alias: "皮革靴子", weight: 10, url: "https://i.postimg.cc/13D7Yym0/pigexuezi.webp" },
          { item: "furou", alias: "腐肉", weight: 10, url: "https://i.postimg.cc/g0YsSRBd/furou.webp" },
          { item: "mugun", alias: "木棍", weight: 5, url: "https://i.postimg.cc/c1KpBynh/mugun.webp" },
          { item: "shuiping", alias: "水瓶", weight: 10, url: "https://i.postimg.cc/rsvgQP7Y/yaoshui.webp" },
          { item: "gutou", alias: "骨头", weight: 10, url: "https://i.postimg.cc/C15NY0gQ/gutou.webp" },
          { item: "monang", alias: "墨囊", weight: 1, url: "https://i.postimg.cc/fknjx00G/mo-nang.webp" },
          { item: "banxiangou", alias: "绊线钩", weight: 10, url: "https://i.postimg.cc/2SN2WgQ1/banxiangou.webp" }
        ];
        selection = weightedRandom(rubbish);
        aliases = rubbish;
      } else {
        const baozang = [
          { item: "gong", alias: "弓", weight: 17, url: "https://i.postimg.cc/wB0VSvSN/gong.webp" },
          { item: "fumoshu", alias: "附魔书", weight: 16, url: "https://i.postimg.cc/WbgxxGSJ/fumoshu.gif" },
          { item: "diaoyugan", alias: "钓鱼竿", weight: 17, url: "https://i.postimg.cc/Vk94W4gD/diaogan.webp" },
          { item: "mingmingpai", alias: "命名牌", weight: 16, url: "https://i.postimg.cc/4yhQ71nv/mingmingpai.webp" },
          { item: "yingwuluoke", alias: "鹦鹉螺壳", weight: 17, url: "https://i.postimg.cc/dQXWshDm/yingwuluoke.webp" },
          { item: "an", alias: "鞍", weight: 17, url: "https://i.postimg.cc/MKQ9vzQk/an.webp" }
        ];
        selection = weightedRandom(baozang);
        aliases = baozang;
      }

      const selectedItem = aliases.find(item => item.item === selection);
      const expGain = Math.floor(Math.random() * 6) + 1;

      let user = await ctx.database.get('user', { id: userId });
      if (!user.length) {
        user = [{
          id: userId,
          exp: 0,
          items: {},
          name: '',
          flag: 0,
          authority: 0,
          locales: [],
          permissions: [],
          createdAt: undefined
        }];
      }

      const updatedUser = user[0] as User;

      updatedUser.exp += expGain;
      updatedUser.items[selectedItem.item] = (updatedUser.items[selectedItem.item] || 0) + 1;

      await ctx.database.upsert('user', [updatedUser]);

      return (`你钓到了: ${selectedItem.alias} ,\n ${h.image(selectedItem.url)} 并获得了 ${expGain} 点经验!`);
    });
}

改成这样可否,VSCode没有报错
只是有个问题:使用koishi沙盒功能测试是提示无法获取ID

1 个赞

你在干什么,你应该改类型的名字,然后参考文档,而不是导入一个别的类型

1 个赞