0

I have the following object that who's structure I'd like to enforce.

{
    'username': {
      required: 'Please enter your username.'
    },
    'passwordGroup': {
      ocMatchFields: 'Passwords do not match'
    },
    'passwordGroup.password': {
      required: 'Please enter your password'
    },
    'passwordGroup.confirmPassword': {
      required: 'Please confirm your password'
    }
}

It'll never be more deeply nested than shown and the values will always be strings but there can be any number of "fields". fields in this case are first level keys. username, passwordGroup etc.

I had come across something that describes an object as { [key: string]: boolean } which makes me believe its possible.

I can think of how to represent it as a collection since that would be an array of objects but I'm not sure how I'd be able to describe it as a nested object structure.

Crhistian Ramirez
  • 1,066
  • 12
  • 20

5 Answers5

3

Knowing TypeScript, there's probably some awesome syntax I've overlooked. But here's one way:

interface StringToString { [key: string]: string };
interface MyNested { [key: string]: StringToString };

let x: MyNested = {
    'username': {
        required: 'Please enter your username.'
    },
    'passwordGroup': {
        ocMatchFields: 'Passwords do not match'
    },
    'passwordGroup.password': {
        required: 'Please enter your password'
    },
    'passwordGroup.confirmPassword': {
        required: 'Please confirm your password'
    }
}

Note that the above doesn't prevent the nested object from having more than one key.

Or you could get super generic (but it's probably overkill):

interface KeyValuePair<T> { [key: string]: T };

let x: KeyValuePair<KeyValuePair<string>> = {
    'username': {
        required: 'Please enter your username.'
    },
    'passwordGroup': {
        ocMatchFields: 'Passwords do not match'
    },
    'passwordGroup.password': {
        required: 'Please enter your password'
    },
    'passwordGroup.confirmPassword': {
        required: 'Please confirm your password'
    }
}
Frank Modica
  • 10,238
  • 3
  • 23
  • 39
0

Well, you can do this.

export default [
{
    'username': {
      required: 'Please enter your username.'
    },
    'passwordGroup': {
      ocMatchFields: 'Passwords do not match'
    },
    'passwordGroup.password': {
      required: 'Please enter your password'
    },
    'passwordGroup.confirmPassword': {
      required: 'Please confirm your password'
    }
}
]

later, on your typescript controller, you can import it as whatever you want to call it

import nameYouWant from 'adrees-file-src-exist-json'
Kenry Sanchez
  • 1,703
  • 2
  • 18
  • 24
0

You can declare an object of that type this way:

myObject: {
  'username': {
    required: string
  },
  'passwordGroup': {
    ocMatchFields: string;
  },
  'passwordGroup.password': {
    required: string
  },
  'passwordGroup.confirmPassword': {
    required: string
  }
}

This way you can do then:

myObject.username, ...

you have then only those properties inside that object.

you cannot affect another object having another property than username or passwordGroup, etc ...

HDJEMAI
  • 9,436
  • 46
  • 67
  • 93
  • The geneeric structure is really what I'm trying to model, the object I gave is simply an example. I don't know ahead of time what the properties of the object will be. – Crhistian Ramirez Dec 26 '17 at 04:00
  • well fine, I have used this way a number of times because I was in need to have an object having only predefined properties. – HDJEMAI Dec 26 '17 at 04:02
  • Yeah, that totally makes sense in that use case. Thank you for your time and answer. – Crhistian Ramirez Dec 26 '17 at 04:03
0

TypeScript 2.2 introduced a new type called object. It represents any non-primitive type. The following types are considered to be primitive types in JavaScript:

boolean
number
string
symbol
null
undefined

All other types are considered to be non-primitive types. The new object type represents exactly these:

All primitive types

type Primitive = | boolean | number | string | symbol | null | undefined;

All non-primitive types

type NonPrimitive = object;

Let's see how object lets us write more accurate type declarations. Type Declarations Using the Object Type

With the release of TypeScript 2.2, the type declarations for the standard library have been updated to make use of the new object type. For instance, the Object.create() and Object.setPrototypeOf() methods now specify the type object | null for their prototype parameters:

Abhishek Ekaanth
  • 2,511
  • 2
  • 19
  • 40
0

Please declare these types in LoginInterface.ts

export interface IfcRequired {
    required: String;       
}

export interface IfcOCMatchFields {
    ocMatchFields: String;
}

export interface Login {
    username: IfcRequired;
    password: IfcOCMatchFields;
    passwordGroup.password: IfcRequired;
    passwordGroup.confirmPassword: IfcRequired;   
}

For using these interfaces, please use

import {IfcRequired, IfcOCMatchFields, Login} from 'LoginInterface';

For declaring a type for an array of Login Object

let login: Login[];

I would suggest you to create a Login class for inserting data inside login variable.

Ajay
  • 4,773
  • 3
  • 23
  • 36
  • If we know the property names ahead of time this might be the way to go, but I was under the assumption that we don't know them – Frank Modica Dec 26 '17 at 04:24
  • @FrankModica, If we are unsure about the field names than we should surely use the Generic Type which can be object, array, any etc. In that case declaring a type for a variable isn't going to be that much fruitful. – Ajay Dec 26 '17 at 04:27
  • 1
    Without knowing the property names you could still constrain the keys to be any string or number (which are the only 2 types that TypeScript allows as keys), and you could constrain the values to a certain type – Frank Modica Dec 26 '17 at 04:30
  • key can take only string type in an object. If we pass the key as a number than the JS is going to consider it as an Array If the object is not initialized yet. Though we can surely define the type of values. – Ajay Dec 26 '17 at 04:34
  • I believe you're right about numbers being converted to strings (at runtime) when used as keys for objects (although TypeScript still allows you to type the key as a number at dev time). But I do not believe JS will consider an uninitialized object to be an array if you use a number as an index. For example, if you try to iterate over the object using the `let val of arr` syntax it won't work. Also it won't have a `.length` property, etc. But maybe I misunderstood? – Frank Modica Dec 26 '17 at 04:44
  • You are right. I misinterpreted it and wrote that after checking it in the console. I should have checked it with .length property. Thanks for correcting me. – Ajay Dec 26 '17 at 04:48