admin管理员组

文章数量:1405170

I have a data class

export interface MusicDto {
    title?: string;
    artist?: string;
    //...
}

I would like to fill it with data from key/value tokens

tokens.forEach(token => {
  const [key, value] = token.split(':');
  if (key && value) {
    const propertyName = key.trim().toLowerCase() as keyof MusicDto;
    const propertyValue = value.replace(';', '').trim();
    let targetProperty = musicData[propertyName];

    if (targetProperty) {
      switch (typeof targetProperty) {
        case 'string': targetProperty = propertyValue;
          break;
        case 'number': targetProperty = parseFloat(propertyValue);
          break;
        default:
      }
    } else {
      console.log(`Unknown property ${propertyName}`);
    }
  }
});

But all properties are going to "Unknown property"

Here a playground which reproduces it

I have a data class

export interface MusicDto {
    title?: string;
    artist?: string;
    //...
}

I would like to fill it with data from key/value tokens

tokens.forEach(token => {
  const [key, value] = token.split(':');
  if (key && value) {
    const propertyName = key.trim().toLowerCase() as keyof MusicDto;
    const propertyValue = value.replace(';', '').trim();
    let targetProperty = musicData[propertyName];

    if (targetProperty) {
      switch (typeof targetProperty) {
        case 'string': targetProperty = propertyValue;
          break;
        case 'number': targetProperty = parseFloat(propertyValue);
          break;
        default:
      }
    } else {
      console.log(`Unknown property ${propertyName}`);
    }
  }
});

But all properties are going to "Unknown property"

Here a playground which reproduces it

Share Improve this question edited Mar 8 at 23:31 Jason Aller 3,65228 gold badges41 silver badges39 bronze badges asked Mar 8 at 19:56 FoxhuntFoxhunt 9222 gold badges13 silver badges31 bronze badges 3
  • What is musicData and what is the significance of musicData[propertyName]? I don't get why you've called the result of that targetProperty when it will be the value of the property. And even then, it will only be the value if that is already set. But even assuming you get over these hurdles assigning to targetProperty is not going to do anything at all. – VLAZ Commented Mar 8 at 20:56
  • assigning to a local variable targetProperty doesnt change musicData, please reproduce your problem on typescriptlang./play – Alexander Nenashev Commented Mar 8 at 22:27
  • I did a playground to clarify it (Added at the end of question) – Foxhunt Commented Mar 8 at 23:05
Add a comment  | 

1 Answer 1

Reset to default 1

You cannot fill an object this way by assigning to it's extracted value. You need to refer to the property directly. Also your initial class instance is totally empty so you can't get any runtime types from it.

A solution with fixes for these problems:

// Here the data
const anExampleVariable =  `
#TITLE:ROOM;
#ARTIST:Blanc Bunny Bandit;
#BANNER:ROOM.png;
#BACKGROUND:ROOM-bg.png;
#CDTITLE:./CDTitles/DDR A20 PLUS.png;
#MUSIC:ROOM.ogg;
#SAMPLESTART:57.5;
#SAMPLELENGTH:15;
#BPMS:0=145;
`
const tokens = anExampleVariable.split('#').map(token => token.trim()).filter(token => token.length > 0);

// Here my target DTO
class MusicDto {
  title?: string = '';
  artist?: string = '';
  banner?: string = '';
  background?: string = '';
  cdTitle?: string = '';
  music?: string = '';
  sampleStart?: number = 0;
  sampleLength?: number = 0;
  bpms?: string = '';
  notes: number[][][] = [];
}

const musicData: MusicDto = new MusicDto()

const newData = tokens.reduce((r, item) => {
  const [key, value] = item.split(':');
  r[key.toLowerCase()] = value.slice(0,-1);
  return r;
}, {} as Record<string, string>);

const foundKeys: string[] = [];
const keys = <T extends object>(obj: T) => Object.keys(obj) as (keyof T)[];
keys(musicData).forEach(name => {
  const lower = name.toLowerCase();
  if(lower in newData){
    foundKeys.push(lower);
    const value = newData[lower];
    if(typeof musicData[name] === 'string'){
      (musicData as any)[name] = value; // you could use a custom type guard
    }else if(typeof musicData[name] === 'number'){
      (musicData as any)[name] = parseFloat(value); // you could use a custom type guard
    }
  }
});

const notFoundKeys = Object.keys(newData).filter(k => !foundKeys.includes(k));

console.log('not found:', notFoundKeys);

console.log(musicData)

本文标签: typescriptFill class properties with keyvalue dataStack Overflow