Angular Interface with Enum - javascript

is possible to have an interface with enum at angular ?
I have an interface like this:
export interface UserModel {
title: TitleEnum
}
An Enum:
export enum TitleEnum {
Admin = 0,
Alfa = 1,
Beta = 2
}
So I am trying to get {{user.title}}, keep receiving the numbers, am I missing something?

This is how enums work! If you are looking assign the keys to strings, then you can use a string enum.
export enum TitleEnum {
Admin = 'Admin',
Alfa = 'Alfa',
Beta = 'Beta'
}

What you can also do is to use a property
//in your component html
<select>
<option *ngFor="let key of keys" [value]="key" [label]="race[key]"></option>
</select>
export enum RaceCodeEnum {
Asian = 1,
Mexican = 2,
AfricanAmerican = 3,
White = 4,
}
export class RaceSelect {
race= RaceCodeEnum;
constructor() {
this.keys = Object.keys(this.race).filter(k => !isNaN(Number(k)));
}
}

Related

typescript: How to define type as any part of enum?

I'm trying to create a translation module using typescript.
I want to define the languages as an enum parameter to create-text function, as like:
export enum Language {
He = "he",
En = "en",
}
const { createI18n, createI18nText } = createTextFunctions(Language);
const firstExample = createI18nText({
he: {
firstText: "שלום",
sc: {
hello: "שלום שוב"
}
},
en: {
firstText: "hello",
sc: {
hello: "hello again"
}
}
})
export const i18n = createI18n({
welcome: firstExample,
})
But my problem is that because the languages are are passed as params to a typescript function and the function infers the types, typescript is not alarming anything. I can create text with non-existing language and it will pass it,like createI18nText({ ar:{ hi : "hi" }}).
My text functions are these:
export type Languages = { [key: string]: string };
export const createTextFunctions = (languages: LanguagesD) => {
type I18nText<T extends object> = {
[k in keyof typeof languages]: T;
}
const createI18n = <T extends { [key: string]: I18nText<any>; }>(i18n: T) => {
return i18n;
};
const createI18nText = <T extends object>(text: I18nText<T>) => {
return text;
}
return {
createI18n,
createI18nText
}
}
So the code is running and doing whatever it needs to do, but I'm losing type control.
I do prefer to have my enum values lower-cased, so its an issue too. If this is the solution so I'll take it, but if there is any way to pass an enum-param and to run by its values it would be great.
You can make createTextFunctions use a generic. You will be able to customise the keys as you want when you create the text function :
// *L* must be a union of strings.
const createTextFunctions = <L extends string>() => {
type I18nText<T extends object> = Record<L, T>;
type I18n = Record<string, I18nText<any>>;
const createI18n = <T extends I18n>(i18n: T): T => {
return i18n;
};
const createI18nText = <T extends object>(text: I18nText<T>): I18nText<T> => {
return text;
}
return {
createI18n,
createI18nText
}
}
Then specify the Language as a union of strings:
type Language = "en" | "he";
And create/use the text functions:
const { createI18n, createI18nText } = createTextFunctions<Language>();
const firstExample = createI18nText({
he: {
firstText: "שלום",
sc: {
hello: "שלום שוב"
}
},
// If the key *en* is missing, typescript will complain.
en: {
firstText: "hello",
sc: {
hello: "hello again"
}
},
// If we add the key *us*, typescript will complain.
})
export const i18n = createI18n({
welcome: firstExample,
})
IMO union types are more comfortable to use than enums.

can't 'convert' typescript definition in javascript

I am trying to rewrite this Apollo typescript repository to javascript.
I try to learn typescript but there is one thing called 'type casting' or 'type assertion' which makes me confuse.
let me explain it with code:
//cache.tsx
import { InMemoryCache, ReactiveVar, makeVar } from "#apollo/client";
import { Todos } from "./models/Todos";
import { VisibilityFilter, VisibilityFilters } from "./models/VisibilityFilter";
export const cache...{
...
...
}
export const todosVar: ReactiveVar<Todos> = makeVar<Todos>( //how i can 'convert' this type caster value to vanilla js?
todosInitialValue
);
export const visibilityFilterVar = makeVar<VisibilityFilter>( //how i can 'convert' this type caster value to vanilla js?
VisibilityFilters.SHOW_ALL
)
other 2 files which are used by this cache.tsx are:
//todos.tsx
export interface Todo {
text: string;
completed: boolean;
id: number
}
export type Todos = Todo[];
and
VisibilityFilter.tsx
export type VisibilityFilter = {
id: string;
displayName: string;
}
export const VisibilityFilters: { [filter: string]: VisibilityFilter } = {
SHOW_ALL: {
id: "show_all",
displayName: "All"
},
SHOW_COMPLETED: {
id: "show_completed",
displayName: "Completed"
},
SHOW_ACTIVE: {
id: "show_active",
displayName: "Active"
}
}
How can I avoid typescript type checking in this situation and more important, how can I use ReactiveVar and makeVar imports properly?
Just remove the generic like this:
From:
makeVar<Todos>(
To:
makeVar(
Change this:
export const todosVar: ReactiveVar<Todos> = makeVar<Todos>( //how i can 'convert' this type caster value to vanilla js?
todosInitialValue
);
export const visibilityFilterVar = makeVar<VisibilityFilter>( //how i can 'convert' this type caster value to vanilla js?
VisibilityFilters.SHOW_ALL
)
To this:
export const todosVar = makeVar(todosInitialValue);
export const visibilityFilterVar = makeVar(VisibilityFilters.SHOW_ALL);
How to avoid typescript checking - replace your extensions from .ts and .tsx to .js and .jsx respectively.

an create type using key in enum has implicitly 'any' problem [angular]

Why does the key of [type] need a type? It's really weird to say that, but I have a problem.
data example:
export enum ENUM_Bike {
suzuki = 'suzuki',
yamaha = 'yamaha',
kawasaki = 'kawasaki'
}
export type TBike_StringMapping = { [key in ENUM_Bike]: string };
export const CONST_BikeIconName: Readonly<TBike_StringMapping> = {
suzuki : 'icon_a',
yamaha : 'icon_b',
kawasaki : 'icon_c',
}
export const CONST_BikeIconColor: Readonly<TBike_StringMapping> = {
suzuki : '#111',
yamaha : '#222',
kawasaki : '#333',
}
using
<mat-icon
*ngFor="let item of CONST_BikeIconName | keyvalue: orderByJson"
[ngStyle]="{'background-color': CONST_BikeIconColor[item.key] }">
{{ item.value }}
</mat-icon>
I have been using it like this, but now it appears
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Readonly<TBike_StringMapping>'.
No index signature with a parameter of type 'string' was found on type 'Readonly<TBike_StringMapping>'.ts(7053)
I found a discussion, but it can't solve my problem. I need type not interface. Can anyone help me? thanks for the help.
TypeScript TS7015 error when accessing an enum using a string type parameter
Edit to Rachid O: there has same example here, and same error
error example on typescriptlang.org
one quick solution for this problem would be to exactly do what the compiler suggests and add an intermediate type that has an index signature like so :
export interface TBike_StringMappingExtended extends TBike_StringMapping {
[key: string]:string
}
this will give :
export enum ENUM_Bike {
suzuki = 'suzuki',
yamaha = 'yamaha',
kawasaki = 'kawasaki'
}
export type TBike_StringMapping = Record<ENUM_Bike, string>;
export interface TBike_StringMappingExtended extends TBike_StringMapping {
[key: string]:string
}
export const CONST_BikeIconName: TBike_StringMappingExtended = {
suzuki : 'icon_a',
yamaha : 'icon_b',
kawasaki : 'icon_c',
}
export const CONST_BikeIconColor: TBike_StringMappingExtended = {
suzuki : '#111',
yamaha : '#222',
kawasaki : '#333',
}
for (let key in CONST_BikeIconName) {
if (key) {
const element = CONST_BikeIconColor[key];
}
}

Indexing Object using Enum

I have the following structure;
import data from "../data.min.json";
export enum TileType {
tree = 'tree',
rock = 'rock'
}
interface MapTile {
walkable: boolean;
positions: number[][];
}
export type MapTiles = {
[key in TileType]: MapTile
}
export interface Level1 {
mapTiles: MapTiles;
}
export interface RootObject {
level_1: Level1;
}
export default data as RootObject;
This works fine. However, when I try to use it like so;
const entries = Object.entries(data.level_1.mapTiles);
entries.forEach(([tileType, data]) => {
})
The value of tileType is a string, rather than an Enum. How can I get the enum value instead?
data structure:
{
"level_1": {
"mapTiles": {
"tree": {
"walkable": false,
"positions": [
[ 0, 0 ], [ 0, 40 ], [ 0, 80 ]]
},
"rock": {
"walkable": false,
"positions": [
[2, 4], [5, 7]
]
},
}
}
}
This has to do with the typings for Object.entries in lib.esXXX.object.d.ts. In lib.es2017.object.d.ts for example, the typings look like this:
entries<T>(o: { [s: string]: T } | ArrayLike<T>): [string, T][];
As you can see, the key is assumed to be a string. If you instead changed it like so, things would work as you expect:
entries<T, U extends keyof T>(o: T): [U, T[U]][];
Now you obviously wouldn't want to update the typings on a standard library - so you could instead create your own typed function like so:
const objectEntries = <T, U extends keyof T>(inputObject: T) => {
return Object.entries(inputObject) as [U, T[U]][]
}
Using this you should get the typings you're looking for, and
objectEntries(data.level_1.mapTiles).forEach(([
tileType, // correctly inferred as "tree" | "rock"
data
]) => {})

StencilJS export custom class

Is there any way to force StencilJS to export enums in order to be used by regular JavaScript code?
Generated JavaScript file exports the component classes only.
export { Calendar, CalendarDailyView, CalendarMonthlyView, CalendarWeeklyView, CalendarYearlyView };
It does not export other classes or Enums defined using JavaScript.
let's say an Enum is defined in TypeScript as follows:
export enum ViewType {
daily = 0,
weekly = 1,
monthly = 2,
yearly = 3
}
the generated JavaScript file contains:
var ViewType;
(function (ViewType) {
ViewType[ViewType["daily"] = 0] = "daily";
ViewType[ViewType["weekly"] = 1] = "weekly";
ViewType[ViewType["monthly"] = 2] = "monthly";
ViewType[ViewType["yearly"] = 3] = "yearly";
})(ViewType || (ViewType = {}));
how to force StencilJS to add ViewType to the exported types list?
Enum is entirely a TypeScript concept. JavaScript has no concept of Enums, and the generated code you see is the 'best' solution that TypeScript can generate, given all of the functionality TypeScript Enums have.
To make it compatible with plain old JavaScript it might be worth declaring ViewType as a basic array, e.g.
export const ViewType = [
{ id: 1, name: 'Day' },
{ id: 2, name: 'Month' },
{ id: 3, name: 'Year' }
];
Much easier to interpret in JS than the compiled TypeScript, and a better solution if you're going to be rendering any of these data to the screen.
To make this answer Stencily, here's my example in use:
list-items.ts
export const ListItems = [
{ id: 1, name: 'Day' },
{ id: 2, name: 'Month' },
{ id: 3, name: 'Year' }
];
my-dropdown.tsx
import { Component, State } from '#stencil/core';
import { ListItems } from './list-items';
#Component({
tag: 'my-dropdown'
})
export class MyDropdown {
#State() state: { selectedId?: number } = {};
private onSelectedValueChanged(evt: UIEvent) {
this.state = { ...this.state, selectedId: parseInt((evt.target as HTMLInputElement).value) };
}
render() {
return (
<div>
<select onChange={this.onSelectedValueChanged.bind(this)}>
<option>Please select...</option>
{ListItems.map(i => <option value={i.id}>{i.name}</option>)}
</select>
<br />Selected ID: {this.state.selectedId}
</div>
);
}
}
Important: To reuse your exported collection or enum in other applications, be sure to build as dist (see outputTargets documentation in your stencil.config.js.
In this example, building as dist will include the separate export in /dist/collection/my-dropdown/list-items.js so that it can be re-used in other dependent apps and libraries.

Categories