Вот класс:
const COMMANDS = [
"get-myanimelist-staff-urls",
"get-myanimelist-anime-explicit-genres",
"get-myanimelist-anime-genres",
"get-myanimelist-anime-themes"
...
];
class Shiinobi {
constructor() {
COMMANDS.forEach((command) => {
this[command.replaceAll("-", "_")] = async (...args: any[]) => {
const id = args[0];
return await this.#spawn({ command, id: id });
};
});
}
...
и я использую этот класс Shiinobi например:
const shiinobi = new Shiinobi();
const res = await shiinobi.get_myanimelist_staff_urls();
По сути, это правильный код, поскольку constructor создает такие методы.
но для таких методов нет типа:
shiinobi.get_myanimelist_staff_urls()
этот код показывает ts-error
Я пробовал использовать машинописный текст, изготовленный по индивидуальному заказу Utility, но надежды не было.
Редактировать:
вот код репозитория GitHub
Короткие вопросы: 1. Вам нужно, чтобы динамические методы были доступны изнутри класса Shiinobi? 2. Каким должен быть тип возвращаемого значения для ваших методов?
Добро пожаловать в Stack Overflow! • Пожалуйста, отредактируйте , чтобы предоставить минимально воспроизводимый пример без ссылок на необъявленные вещи (например, #spawn), но со всей информацией о полученном вами сообщении об ошибке.
(см. предыдущий комментарий) • Чего именно вы ожидаете? TS не поддерживает по-настоящему динамические ключи в объявлении класса; самое близкое, что вы можете получить, — это индексная подпись. Должны ли ключи быть статически известны из содержимого COMMANDS? Если да, то replaceAll() недостаточно строго типизирован для преобразования типов строковых литералов. Я мог бы предположить что-то вроде это то, что вы хотите, но было бы очень полезно, если бы вы отредактировали, чтобы уточнить.
@DerekRoberts журналов ошибок не было, просто машинописный текст не мог понять их типы. Я заставил его замолчать с помощью // @ts-ignore
@moonstar-x 1. Нет, я не хочу получать к нему доступ изнутри (извините, я забыл добавить полный код класса). 2. Это должно быть обещание типа:Promise<any>
@jcalz да, извини, только что сделал :)
Привет, я только что отредактировал свой вопрос, исправив его, и мне интересно, есть ли лучший способ сделать это. вот тс площадка моего текущего исправления.
«Журналов ошибок не было, просто машинописный текст не мог понять их типы». Итак, были журналы ошибок, когда вы запускали tsc или вводили ошибки в вашей IDE. Пожалуйста, отредактируйте , чтобы включить их. См. мой комментарий о минимально воспроизводимом примере , включая #spawn и т. д. Согласно коду, который вы здесь представили, ваш тип утилиты не должен работать, потому что COMMANDS имеет тип string[] (может быть, вы хотите as const там, но здесь его нет). ). Я вижу, что у вас есть ссылка на ваш код на github, но это не считается минимально воспроизводимым примером. Весь соответствующий код должен быть в вопросе в виде обычного текста.
(пожалуйста, посмотрите предыдущий комментарий и ответьте). Если вы нашли исправление (хотя оно похоже на другие ответы, представленные здесь), то его следует опубликовать в ответе, а не как редактирование вопроса. Просьбы о лучших способах выполнения задач становятся менее подходящими для Stack Overflow и более подходящими для Code Review , поэтому я бы посоветовал вам не делать этого здесь. Также обратите внимание, что нигде в вопросе вы не указали, что хотите (id?: number) => Promise<any>, это только в вашем отредактированном решении. Если вы опубликуете ответ, нам все равно понадобится минимально воспроизводимый пример, который его мотивирует.
@jcalz привет, извини, я не знал о стандартах Stack Overflow (это был мой первый раз). в любом случае, я опубликовал ответ с примером. надеюсь, в этот раз все будет хорошо :)






Вы можете сначала объявить некоторые типы:
const COMMANDS = [
"get-myanimelist-staff-urls",
"get-myanimelist-anime-explicit-genres",
"get-myanimelist-anime-genres",
"get-myanimelist-anime-themes"
// ...
] as const;
type COMMANDS_TYPE = typeof COMMANDS;
type ReplaceDashWithUnderscore<T extends string> =
T extends `${infer P1}-${infer R1}` ? `${P1}_${ReplaceDashWithUnderscore<R1>}` :
T extends `${infer P2}-${infer R2}` ? `${P2}_${ReplaceDashWithUnderscore<R2>}` :
T extends `${infer P3}-${infer R3}` ? `${P3}_${ReplaceDashWithUnderscore<R3>}` :
T extends `${infer P4}-${infer R4}` ? `${P4}_${ReplaceDashWithUnderscore<R4>}` :
T extends `${infer P5}-${infer R5}` ? `${P5}_${ReplaceDashWithUnderscore<R5>}` :
T;
type Underscore<T extends COMMANDS_TYPE> = {
[K in keyof T]: T[K] extends string ? ReplaceDashWithUnderscore<T[K]> : never;
};
type ToObj<T extends Underscore<COMMANDS_TYPE>> = {
// TODO Should Promise<void> be Promise<return type of spawn>
[K in T[number]]: (id: string, ...args: any[]) => Promise<void>;
};
Вышеупомянутое позволяет вам определить объект с помощью команд как методов в правильном формате:
Тогда вместо использования класса вы можете использовать фабрику для литерала объекта. С этим будет проще справиться при использовании динамических свойств:
function shinobiFactory() {
// private stuff
const somethingPrivate: number = 0;
interface SpawnConfig {
command: typeof COMMANDS[number];
id: string;
}
function spawn(config: SpawnConfig) {
return somethingPrivate;
}
function someOtherMethod() {
return somethingPrivate;
}
function underscore<T extends string>(s: T) {
return s.split("-").join("_") as ReplaceDashWithUnderscore<T>;
}
const commandProps = COMMANDS.reduce(
(prev, curr) => {
const key = underscore(curr)
const value = async (id: string, ...args: any[]) => {
return await spawn({ command: curr, id: id });
};
const update = {
...prev,
...{
[key]: value
}
};
return update;
},
{}
) as ToObj<Underscore<COMMANDS_TYPE>>;
// Return only what you want to be public
return {
...commandProps,
someOtherMethod
}
}
Наконец, вы можете вызвать метод для создания экземпляров вашего «класса». Как видите, и свойства, и аргументы верны:
привет, да, это действительно близко к тому, что мне нужно (извините, я не смог добавить полные требования). Мне удалось исправить это с помощью такой специальной утилиты, я новичок в машинописном тексте, можете ли вы проверить мой отредактированный вопрос? Спасибо :)
В итоге я использовал специальную утилиту , которая заменяет - на _ и расширяет интерфейс Shiinobi.
Вот измененный код:
type Command = (typeof COMMANDS)[number];
type ReplaceHyphens<T extends string> = T extends `${infer P1}-${infer P2}`
? `${P1}_${ReplaceHyphens<P2>}`
: T;
type ShiinobiProperties = {
[K in Command as ReplaceHyphens<K>]: (id?: number) => Promise<any>;
};
interface Shiinobi extends ShiinobiProperties {}
Привет, пожалуйста, можете ли вы предоставить всю информацию об ошибке.