Express unknown string object key in TypeScript - json

I'm creating a TypScript Declaration file for a client library with a method that returns an object having a variable string key (a record id):
getRecords(...): {
[string]: { // ??
first: string,
last: string,
...
}
};
What is the correct way to specify that the key value is only known at runtime, and what is the reference for this?
getRecords returns something like:
{
'GuT9b...pX': {
first: 'John',
last: 'Doe',
...
},
'aMe4T...lk': {
first: 'Jane',
last: 'Doe',
....
}
}
(Note that this is a wrapper for an HTTP API written in PHP so I have no control over the result being an associative array (i.e. JavaScript hash), instead of an array with an .id field in each element.)

It's called indexable type:
function getRecords(key: string): { [s: string]: { first: string /*, ...*/ } } {
return { [key]: { first: 'John' } }
}

Related

Adding types to JSON object stored locally in TypeScript

This is the JSON Object that is stored locally
{
"data": {
"John Doe": {"id":"1234", "username":"johndoe"},
"Sia Xander": {"id":"1235", "username":"siax"}
}
}
This is the TypeScript file that I have and I have created this function but it errors out
import { data } from "../Assets/data.json"
function createData(member: string, id: string, username: string) {
return { member, id, username }
}
interface Rows {
member: string
id: string
username: string
}
const rows: Rows[] = []
Object.keys(data).map(member =>
rows.push(
createData(
member,
data[member]["id"], //error
data[member]["username"] //error
)
)
)
I get the following error
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type "data": {
"John Doe": {"id":string, "username":string},
"Sia Xander": {"id":string, "username":string}
}
}
No index signature with a parameter of type 'string' was found on type
"data": {
"John Doe": {"id": string , "username":string},
"Sia Xander": {"id":string, "username":string}
}
}
How do I tell TypeScript that "John Doe" and "Sia Xander" are strings?
Or should I change the way I have made the JSON
Why it doesn't work:
This doesn't work because Object.keys() can return keys not present on the type of its argument. See this answer for more details.
What would work instead:
Instead, try using Object.entries:
Object.entries(data).map(([member, memberData]) =>
rows.push(
createData(
member,
memberData["id"],
memberData["username"]
)
)
);
Object.entries returns key value pairs, so you don't need to do the lookup yourself. See the documentation for more information.
Also, you can use .map in a simpler way:
The way you're using .map works, but you can make it even simpler.
.map returns an array, so you don't need to use push().
Instead, try this:
const rows: Rows[] = Object.entries(data).map(([member, memberData]) =>
createData(
member,
memberData["id"],
memberData["username"]
)
);

Add custom input type to graphql-tag mutation

My django mutation is passing data variable as graphene.JSONString() so my $data variable needs to be or JSON or Object type. Is here any way to achieve that??
I was trying to use scalar JSON but i'me getting an error
I'm getting an error when I'm using: $data: JSON!
export const UPLOAD_SPECIFICATION = gql`
scalar JSON
mutation ($account_id: String!, $name: String, $description: String, $data: JSON!){
uploadSpecification(account_id: $account_id, name:$name, description: $description, data: $data) {
specification {
id,
name
}
}
}`;
export const UPLOAD_SPECIFICATION = gql`
mutation ($account_id: String!, $name: String, $description: String, $data: JSONObject){
uploadSpecification(account_id: $account_id, name:$name, description: $description, data: $data) {
specification {
id,
name
}
}
}`;
I need in my schema.graphql the scalar:
scalar JSON
scalar JSONObject
type Mutation{
uploadSpecification(..., data: JSONObject):Specification
}

Return null on update mutation GraphQL and Sequelize

I would like to know why my response is "null" when I execute my mutation please.
My query works : the state is_active become true or false in the database SQL when I execute the request.
When I create, I have a correct response, but not on the update.
Graphql request :
mutation {
updateSequence(id: 4, , input: {is_active: true}) {
is_active
}
}
The response :
{
"data": {
"updateSequence": {
"is_active": null
}
}
}
resolvers.js
Mutation : {
createSequence(_, {input}) {
return models.Sequence.create(input);
},
updateSequence(_, {id, input}) {
return models.Sequence.update(input, {where: {id: id}});
}
}
schema.js
# Sequence
type Sequence {
id: Int!,
code: String,
buckets: [Bucket],
sequence_types : [SequenceType]
is_active: Boolean,
}
# SequenceInput
input SequenceInput {
is_active: Boolean
}
...
type Query {
sequences: [Sequence]
sequence(id: Int): Sequence
}
type Mutation {
createSequence(input: SequenceInput): Sequence,
updateSequence(id: ID!, input: SequenceInput): Sequence
}
schema {
query: Query,
mutation: Mutation
}
SOLVED : Migrate MySQL to Postegres to use returning option (only Postegres)
I migrate my database to use the returning option from Sequelize.
createSequence(_, {input}) {
return models.Sequence.create(input);
},
updateSequence(_, {id, input}) {
return models.Sequence.update(input, {where: {id: id}, returning: true}).then((sequence) => {
return sequence[1][0].dataValues;
});
},
According to Sequelize Documentation:
The create method returns a Promise<Model>, in your case it returns something that matches type Sequence.
The update method instead, returns a Promise<Array<number, number>> and that does not match type Sequence.
The promise returns an array with one or two elements. The first element is always the number of affected rows, while the second element is the actual affected rows (only supported in postgres with options.returning true.)
So either you change the return type of updateSequence into something that matches the return type from models.Sequence.update, OR, you have to build an object that matches type Sequence after the update.

How to delete a Json object in BASH

I have a couple of Json objects and I need to delete one of them if this Json contains specific information. For an example I need to delete if state of the Json object is RUNNING.
INPUT
projects {
key: "ads_evenflow.opt"
value {
name: "ads_evenflow.opt"
state: COMPLETE
result: PASSED
}
}
projects {
key: "alexandria.opt"
value {
name: "alexandria.opt"
state: RUNNING
result: PASSED
}
}
projects {
key: "android.opt"
value {
name: "android.opt"
state: COMPLETE
result: PASSED
}
}
OUTPUT
projects {
key: "ads_evenflow.opt"
value {
name: "ads_evenflow.opt"
state: COMPLETE
result: PASSED
}
}
projects {
key: "android.opt"
value {
name: "androids.opt"
state: COMPLETE
result: PASSED
}
}
Your structure isn't an valid JSON. For such structures you need some more relaxed parser. Fortunately, the JSONY perl module could parse it. From the doc:
JSONY is a data language that is simlar to JSON, just more chill. All
valid JSON is also valid JSONY (and represents the same thing when
loaded), but JSONY lets you omit a lot of the syntax that makes JSON a
pain to write.
The following perl code does what you want.
#!/usr/bin/env perl
use 5.014;
use warnings;
use JSONY;
my $string = slurp_file();
my $data = JSONY->new->load( $string );
for my $proj (#{$data}) {
next unless ref($proj);
next if $proj->{value}->{state} eq 'RUNNING';
pretty_print_proj($proj);
}
sub pretty_print_proj {
my $p = shift;
say "project {";
say qq{\tkey: "$p->{key}"};
say "\tvalue {";
say "\t\t$_: ", $p->{value}->{$_} for (qw(name state result));
say "\t}";
say "}";
}
sub slurp_file {
#change this for your real case...
return do { local $/; <DATA>};
}
__DATA__
projects {
key: "ads_evenflow.opt"
value {
name: "ads_evenflow.opt"
state: COMPLETE
result: PASSED
}
}
projects {
key: "alexandria.opt"
value {
name: "alexandria.opt"
state: RUNNING
result: PASSED
}
}
projects {
key: "android.opt"
value {
name: "android.opt"
state: COMPLETE
result: PASSED
}
}
prints:
project {
key: "ads_evenflow.opt"
value {
name: ads_evenflow.opt
state: COMPLETE
result: PASSED
}
}
project {
key: "android.opt"
value {
name: android.opt
state: COMPLETE
result: PASSED
}
}

Generic return type of function in Typescript

I'm new to ts but I've learnt a little about the concept of generics in java. The query is that I have three functions : searchTrack, searchAlbum, searchArtist
searchTrack(query: string): Observable<Track[]> {
return this.search(query, 'track');
}
searchArtist(query: string): Observable<Artist[]> {
return this.search(query, 'artist');
}
searchAlbum(query: string): Observable<Album[]> {
return this.search(query, 'album');
}
I want a general function 'search' in this class that takes the query and the type of entity and returns an Observable of collection of a specific entity type. I'm stuck here. How can I work with generics to specify a generic return type of a function.
search(query: string, type: string): Observable<Array<T>> {
return this.query(`/search`, [
`q=${query}`,
`type=${type}`
]);
}
Is there any way I can achieve this?
Try using the Array class instead of [].
Also define a generic T type on the search function.
search<T>(query: string, type: string): Observable<Array<T>> {
return this.query(`/search`, [
`q=${query}`,
`type=${type}`
]);
}
You should be able to call it like this:
let result = search<Artist>('someQuery', 'artist');
You can find more about generics in typescript in the Generics chapter in the handbook here.
As #toskv answered, you can add a generics type to the method signature, but the compiler has no way of inferring the type so you'll have to add it:
myObj.search<Track>(query, "track");
However, you can do something like:
interface MyObservableClass {}
interface MyObservableClassCtor<T extends MyObservableClass> {
new (): T;
getType(): string;
}
class Artist implements MyObservableClass {
static getType(): string {
return "artist";
}
}
class Album implements MyObservableClass {
static getType(): string {
return "album";
}
}
class Track implements MyObservableClass {
static getType(): string {
return "track";
}
}
class Searcher {
search<T extends MyObservableClass>(ctor: MyObservableClassCtor<T>, query: string): Observable<T[]> {
return this.query(`/search`, [
`q=${query}`,
`type=${ ctor.getType() }`
]);
}
}
let searcher: Searcher = ...;
searcher.search(Track, "...");
And then the compiler can infer what the T is by providing it with the class (/ctor).
You can do it with overloads:
class A {
search<T>(query: string, type: "Track"): Observable<Track[]>;
search<T>(query: string, type: "Artist"): Observable<Artist[]>;
search<T>(query: string, type: "Album"): Observable<Album[]>;
search<T>(query: string, type: string): Observable<T[]>;
search<T>(query: string, type: string): Observable<T[]> {
return null;
}
}
Which will give you the correct type:
var observable = x.search("test", "Track");
And this will give a compile error on incompatible objects:
var observableError: Observable<Album[]> = x.search("test", "Track");