Расширить экземпляр conv в клиентской библиотеке Node.js для действий в Google v2 при использовании TypeScript

В действиях в клиентской библиотеке Google Node.js v2 есть промежуточное ПО, которое позволяет добавлять свойства или вспомогательные классы к экземпляру conv. Пример из официального руководства по миграции версии 1:

const { dialogflow } = require('actions-on-google');

class Helper {
  constructor(conv) {
    this.conv = conv;
  }

  func1() {
    this.conv.ask(`What's up?`);
  }
}

const app = dialogflow()
  .middleware(conv => {
    conv.helper = new Helper(conv);
  });

app.intent('Default Welcome Intent', conv => {
  conv.helper.func1();
});

Это может нормально работать для простого JavaScript. Но что, если используется TypeScript?

Если код написан на Typescript, TSC жалуется на строки conv.helper = new Helper(conv); и conv.helper.func1();:

[ts] Свойство 'helper' не существует для типа 'DialogflowConversation ‹{}, {}, Contexts>'.

Возможно, я мог бы переписать его на (<any>conv).helper, но это довольно некрасиво. Кто-нибудь знает (лучшее) решение?


person Markus    schedule 18.05.2018    source источник


Ответы (1)


dialogflow функция создания приложения перегружена параметрами универсального типа, которые позволяют переопределить тип беседы, отправляемый через обработчик намерений.

Вам просто нужно создать тип, расширяющий соответствующий тип разговора. Гораздо сложнее сохранить безопасность всех типов, но это выполнимо.

Таким образом, фрагмент, которым вы поделились в TypeScript в наиболее безопасной и универсальной реализации, будет выглядеть следующим образом:

import {
  dialogflow,
  DialogflowConversation,
  DialogflowMiddleware,
  Contexts,
} from 'actions-on-google';

// an interface with the extensions to the Conversation type
interface HelperConversation<
  TData = {},
  TUserStorage = {},
  TContexts extends Contexts = {},
> extends DialogflowConversation<TData, TUserStorage, TContexts> {
  helper: Helper<TData, TUserStorage, TContexts>;
}

// the helper class now passing generic type parameters from the Conversation type
class Helper<TData, TUserStorage, TContexts extends Contexts> {
  constructor(public conv: DialogflowConversation<TData, TUserStorage, TContexts>) {}

  func1() {
    this.conv.ask(`What's up?`);
  }
}

// to keep type security in the middleware, it needs to be functional and of the DialogflowMiddleware type
const middleware: DialogflowMiddleware<HelperConversation> =
  conv => Object.assign(conv, { helper: new Helper(conv) })

// pass the extended Conversation interface into the `dialogflow` function
const app = dialogflow<HelperConversation>()
  .middleware(middleware);

app.intent('Default Welcome Intent', conv => {
  // now conv is of the type `HelperConversation`
  conv.helper.func1();
});

В зависимости от того, насколько безопасным / универсальным должно быть промежуточное ПО TypeScript, вы можете избавиться от многих дополнительных общих параметров с помощью базовых типов объектов, что сокращает большую часть кода.

Вы также можете взглянуть на фрагменты кода TypeScript, предоставленные во время альфа-тестирования, для более подробного использования TypeScript с библиотекой: