Как объявить карту, содержащую определенные свойства, с помощью flowtype & immutable.js
С учетом объекта веб-сайта, созданного таким образом
import {Map} from 'immutable'
const website = new Map({name: 'My Website', url: 'http://www.myw.fr'})
Как я могу объявить тип сайта, который будет представлять собой карту, содержащую именно указанные свойства.
Я знаю, что могу:
declare type websiteType = Map<string,string>
Но я хотел бы быть более конкретным и объявить карту, которая должна содержать свойства name
и url
типа string
.
Возможно ли это?
Ответы
Ответ 1
Надеюсь, я правильно понял ваш вопрос, потому что никогда не использовал карту из "неизменяемой", поэтому я буду использовать es6 Map.
Почему бы вам просто не использовать класс?
class Website extends Map<string, string> {
constructor(name: string, url: string) {
super()
this.set("name", name)
this.set("url", url)
}
}
Таким образом вы можете инициализировать его следующим образом:
const website = new Website("awesome", "www.awesome.com")
а затем выполните операции get и set.
Если вы пропустите параметры, тип потока вызовет ошибку.
Надеюсь, это будет для вас решением.
EDIT:
Вы также можете создать функцию, которая инициализирует вашу карту.
declare type WebsiteType = Map<string, string>
function createWebsite(name: string, description: string) {
const website: WebsiteType = new Map
website.set("name", name)
website.set("description", description)
return website
}
Однако я считаю, что первое решение лучше, потому что оно дает вам тип веб-сайта
и вам не нужно создавать функцию-создатель.
EDIT:
Если вам нужен такой же синтаксис, как вы использовали инициализацию карты,
вы также можете сделать:
class Website extends Map<string, string> {
constructor({name, url, ...rest}) {
super()
this.set("name", name)
this.set("url", url)
for(const name in rest) {
this.set(name, rest[name])
}
}
}
Однако я считаю, что первый имеет смысл.
Ответ 2
Я не думаю, что Map является решением этой проблемы. Вы можете ограничить его использованием перечислений, но это, похоже, не решает проблему. Вот некоторые результаты, которые я получил во время игры:
type MyKeys = 'A' | 'B';
declare type MyMapType = Map<MyKeys, number>;
const TinyMap: MyMapType = Map({
A: 1,
});
// As expected this doesn't give an error
console.log(TinyMap.get('B'));
const MyMap: MyMapType = Map({
A: 1,
B: 2,
});
// Just a 'number'
MyMap.get('A');
// Somewhat surprisingly this works fine
const NewMap = MyMap.set('A', 'a');
// Now of type 'number | string'
NewMap.get('A')
// Forcing the return into the type causes the error that one
// perhaps would expect: 'string This type is incompatible with number'
const AnotherMap: MyMapType = MyMap.set('A', 'a');
Ответ 3
Неизменяемый Map
поддерживает getter/setters, поэтому вы можете рассматривать его точно как простой объект JS. Просто создайте тип с полями, которые необходимо ограничить:
type Website = {
name: string,
url: string,
}
Затем используйте его, где вам нужно:
import {Map} from 'immutable'
const website: Website = new Map({
name: 'My Website',
url: 'http://www.myw.fr'
})
website.name; // No error
website.url; // No error
website.somethingElse; // Error