Доступ к значению, определенному в определении интерфейса машинописного текста - PullRequest
0 голосов
/ 01 сентября 2018

Я новичок в машинописи и у меня есть вопрос о том, что я не могу выглядеть в позе Googleable.

Предположим, я определил этот интерфейс:

interface MyInterface {
  myField: "myValue"
}

Я хочу написать эту строку кода:

const value = MyInterface.myField; // expect value to equal "myValue"

Это не компилируется, но мне интересно, есть ли способ добиться такого поведения. Поскольку значение myField определяется во время компиляции машинописного текста, я считаю, что это должно быть возможно. Но я не могу понять, как это сделать.

Любой совет приветствуется. Спасибо!

Обновление:

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

https://medium.com/@resir014/a-type-safe-approach-to-redux-stores-in-typescript-6474e012b81e

Я также использую Redux-Saga, и, по сути, я пытаюсь создать безопасное для всех принятие каждого.

Предположим, у меня есть два действия, определенные как интерфейсы, как предложено в статье выше:

import { Action } from 'redux'

interface MyActionA extends Action {
  typeString: "MyActionA",
  payload: {
    // omitted
  }
}

interface MyActionB extends Action {
  typeString: "MyActionB",
  payload: {
    // omitted
  }
}

type MyActionBase =
  | MyActionA
  | MyActionB

Есть ли какой-нибудь правильный способ написать следующее?

function* typeSafeTakeEvery<ActionType extends MyActionBase>(saga: Function) {
  const typeString = ActionType.typeString; // <-- I don't know how to write this line
  yield takeEvery(typeString, function*(action: ActionType) {
    yield saga(action);
  });
}

Для любого данного экземпляра этой универсальной функции ему известен статический тип ActionType (либо MyActionA или MyActionB), и что он должен иметь поле «typeString» с «типом» либо «MyActionA», либо «MyActionB». Я хочу использовать этот «тип» в качестве постоянного значения и передать его фактической функции takeEvery.

Я просто далеко отсюда?

1 Ответ

0 голосов
/ 01 сентября 2018

Чтобы определить значение 'myValue' вместо типа 'myValue', вы можете использовать enum вместо interface:

enum MyEnum {
    myField = "myValue"
}

const value = MyEnum.myField;

Обновление

Причина, по которой не компилируется, заключается в том, что ActionType - это то, что называется параметром type , который представляет собой все, что передается в <...> вместо (...), которые известны как значение параметров или, проще говоря, просто параметры.

Поскольку это тип, а не значение, TypeScript удаляет его определение из скомпилированного вывода JavaScript, поэтому вы получаете сообщение об ошибке, что оно используется в качестве значения, даже если это тип. Поэтому, когда компилятор запускается, он оставляет неопределенную ссылку на ActionType, которая нигде не объявлена ​​в JavaScript.

Теперь, чтобы решить вашу проблему, я все же рекомендую использовать enum и передать actionType в качестве параметра значения, позволяя параметру типа ActionType определить его тип и использовать его для объявления локального типа MyAction который расширяет MyActionBase, таким образом выбирая MyActionA или MyActionB неявно в зависимости от переданного строкового литерала.

import { Action } from 'redux'

enum MyActionType {
  MyActionA = 'MyActionA',
  MyActionB = 'MyActionB'
}

interface MyActionA extends Action {
  typeString: MyActionType.MyActionA,
  payload: {
    // omitted
  }
}

interface MyActionB extends Action {
  typeString: MyActionType.MyActionB,
  payload: {
    // omitted
  }
}

type MyActionBase =
  | MyActionA
  | MyActionB

function* typeSafeTakeEvery<ActionType extends MyActionType>(actionType: ActionType, saga: Function) {
  type MyAction = MyActionBase & { typeString: ActionType }

  yield takeEvery(actionType, function*(action: MyAction) {
    yield saga(action);
  });
}

// Usage

typeSafeTakeEvery(MyActionType.MyActionA, ...)
...