Как сделать тип универсальным?
метод sendConfirmMail это отправка почты при регистрации, просто пример реализации, она принимает юзера с интерфейсом IEmailUser который должен передаваться в главный интерфейс IMail и расширять его
export interface IEmailUser { email: string name: string phone: number } async sendConfirmMail(user: IEmailUser) { const mailContent:IMail<IEmailUser> = { to: user.email, subject: 'Confirm registration', //Example template: 'confirmReg', context: { email: user.email, name: user.name, phone: user.phone } } this.mailService.emailSend(mailContent) } |
export interface IEmailUser { email: string name: string phone: number } async sendConfirmMail(user: IEmailUser) { const mailContent:IMail<IEmailUser> = { to: user.email, subject: 'Confirm registration', //Example template: 'confirmReg', context: { email: user.email, name: user.name, phone: user.phone } } this.mailService.emailSend(mailContent) }
после чего уже в сервисе должен в методе emailSend переменная mailData должна иметь интерфейс уже расширеный IMail
export interface IMail<T> { to: string subject: string, template: string, context: T } async emailSend(mailData:IMail<T>) { const urlConfirmAddress = this.configService.get<string>( 'URL_CONFIRM_ADDRESS', ); return this.mailerService.sendMail({ to: mailData.to, subject: mailData.subject, template: join(__dirname, '/../templates', mailData.template), context: mailData.context }).catch((e) => { throw new HttpException( `Ошибка работы почты: ${JSON.stringify(e)}`, HttpStatus.UNPROCESSABLE_ENTITY, ); }); } |
export interface IMail<T> { to: string subject: string, template: string, context: T } async emailSend(mailData:IMail<T>) { const urlConfirmAddress = this.configService.get<string>( 'URL_CONFIRM_ADDRESS', ); return this.mailerService.sendMail({ to: mailData.to, subject: mailData.subject, template: join(__dirname, '/../templates', mailData.template), context: mailData.context }).catch((e) => { throw new HttpException( `Ошибка работы почты: ${JSON.stringify(e)}`, HttpStatus.UNPROCESSABLE_ENTITY, ); }); }
как сделать в IMail context универсальным? потому что интерфейс T изменяемый, как это сделать?
у меня выходит ошибка
Не удается найти имя "T".ts(2304) Параметр "mailData" общего метода из экспортированного класса имеет или использует закрытое имя "T".ts(4073) |
Не удается найти имя "T".ts(2304) Параметр "mailData" общего метода из экспортированного класса имеет или использует закрытое имя "T".ts(4073)
Дополнительно:
какой тип у this.mailerService.sendMail ? Надо на него ориентироваться, ты просто передаешь туда context как есть
import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { MailerService } from '@nestjs-modules/mailer'; import { ConfigService } from '@nestjs/config'; import { join } from 'path'; import { IMail } from './interfaces/mail.interface'; @Injectable() export class MailService { constructor( private readonly mailerService: MailerService, private configService: ConfigService ) {} async emailSend(mailData:IMail<T>) { const urlConfirmAddress = this.configService.get<string>( 'URL_CONFIRM_ADDRESS', ); return this.mailerService.sendMail({ to: mailData.to, subject: mailData.subject, template: join(__dirname, '/../templates', mailData.template), context: mailData.context }).catch((e) => { throw new HttpException( `Ошибка работы почты: ${JSON.stringify(e)}`, HttpStatus.UNPROCESSABLE_ENTITY, ); }); } } |
import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { MailerService } from '@nestjs-modules/mailer'; import { ConfigService } from '@nestjs/config'; import { join } from 'path'; import { IMail } from './interfaces/mail.interface'; @Injectable() export class MailService { constructor( private readonly mailerService: MailerService, private configService: ConfigService ) {} async emailSend(mailData:IMail<T>) { const urlConfirmAddress = this.configService.get<string>( 'URL_CONFIRM_ADDRESS', ); return this.mailerService.sendMail({ to: mailData.to, subject: mailData.subject, template: join(__dirname, '/../templates', mailData.template), context: mailData.context }).catch((e) => { throw new HttpException( `Ошибка работы почты: ${JSON.stringify(e)}`, HttpStatus.UNPROCESSABLE_ENTITY, ); }); } }
context?: { [name: string]: any; }; |
context?: { [name: string]: any; };
итого ты можешь просто написать
export interface IMail { to: string subject: string, template: string, context: Record<string, unknown>; } |
export interface IMail { to: string subject: string, template: string, context: Record<string, unknown>; }
и не заморачиваться с генериком
я заведомо не могу знать каким он будет
Если ты сам не знаешь, то откуда тс это может знать?
mailerService.sendMail готов принять Record< string, unknown >, тебя такой тип тоже устроит, потому незачем что-то придумывать.
Ну а в универсальной функции emailSend всё равно будет достаточно IMail< Record< string, unknown > >
async emailSend(mailData: IMail<Record<string, unknown>>) { |
async emailSend(mailData: IMail<Record<string, unknown>>) {
как альтернатива, вместо Record< string, unknown > здесь можно перечислить через | все возможные варианты контекста:
async emailSend(mailData: IMail<IEmailUser | IEmailOther1 | IEmailOther2 | etc>) { |
async emailSend(mailData: IMail<IEmailUser | IEmailOther1 | IEmailOther2 | etc>) {
но, по моему, это менее гибко.
----
делать emailSend генериком, как предложено в ответе, нет надобности - от этого никаких плюсов. Да и опять же генерик надо будет ограничить типом Record< string, unknown >, чтобы данные можно было передать в mailerService.sendMail
async emailSend<T extends Record<string, unknown>>(mailData: IMail<T>) |
async emailSend<T extends Record<string, unknown>>(mailData: IMail<T>)
Ответы:
async emailSend<T>(mailData: IMail<T>)
- я так делал, ошибка пропадает но тогда в context: mailData.context нет отображаются в подсказках переменные из того самого изменяемого интерфейса
- Александр Иванов, так внутри метода и не известно что пришло. Какую задачу пытаетесь решить?
- Александр, если можно так сказать, универсальную типизацию, т.е. есть главный интерфейс IMail в котором есть элемент context и этот контекст изменяемый, некий T и этот интерфейс T может быть как IEmailUser так и другим передаваемым интерфейсом. чтоб я в конечном итоге мог принимать этот уже "полный" интерфейс, т.е. в данном примере это получается IMail в функции async emailSend(mailData:IMail) и вот как это сделать!
- Александр Иванов, у тебя это уже сделано... Ты не понимаешь чего ты хочешь.
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос
Для сделать тип универсальным в языке программирования PHP, можно использовать ключевое слово "mixed" в объявлении типа переменной или возвращаемом значении функции. Ключевое слово "mixed" позволяет указать, что переменная может содержать значения различных типов данных.
Пример использования ключевого слова "mixed":
function exampleFunction(): mixed { $randomValue = rand(0, 1); if ($randomValue === 0) { return "Hello, World!"; } else { return 42; } } $exampleVariable = exampleFunction(); if (is_string($exampleVariable)) { echo "String value: " . $exampleVariable; } elseif (is_int($exampleVariable)) { echo "Integer value: " . $exampleVariable; }
В приведенном примере функция exampleFunction возвращает значение типа "mixed", которое может быть как строкой, так и целым числом. После вызова функции, мы проверяем тип возвращаемого значения с помощью функций is_string и is_int, и далее выводим соответствующее сообщение в зависимости от типа данных.
Используя ключевое слово "mixed", можно сделать тип переменной или возвращаемого значения функции более универсальным и гибким, что может быть полезно в случаях, когда тип данных может быть неопределенным или изменчивым.