Typescript design pattern for rendering different objects with similarities It's a web project. The code is working. The question is a design pattern question to write code that's more elegant, you know.
I've created a Codepen of this question.
I created a css grid WITHOUT using 'grid' but using float and clear.
I know such project works better written in React but it's just a try.
The grid I'm creating is entirely recreated when calling the render(world) method.
I'm not using any HTML outside of javascript (typescript).
I'm only using 4 CSS classes:
.block-first, .block-lasts {
  width: 20px;
  height: 20px;
  border-radius: 20px;
  float: left;
}

.block-first {
  clear: both;
}

.image-in-block {
  width: 20px;
  height: 20px;
}

.container {
  
}

In the grid are square blocks of equal size being 1- a uniformly colored block or 2- a block containing an image.
So I first fill up a matrix 20x20 of instances of classes that implements a IBlock interface containing a getProperty() method. Those classes are 1- ColorBlock or 2- ImageBlock. Below are these classes and the interface:
interface IBlock {
  getProperty() : string;
}
class ImageBlock implements IBlock{
  url: string;
  constructor(url: string) {
    this.url = url;
  }
  getProperty() : string {
    return this.url;
  }
}
class ColorBlock implements IBlock{
  color: string;
  constructor(hexColor: string) {
    this.color = hexColor;
  }
  getProperty() : string {
    return this.color;
  }
}

My problem is that I need to use different code to render each. For the ColorBlock I'm going with a colored div with background: '#ff00ff'; But for the ImageBlock I'm going with a nested img tag instead of a background-image: url('https://...');.
For distinguishing between the different classes, I'm using object_instance.constructor.name, I think that's the whole problem.
Now the rest of my code:
Matrix prepping:
const world = new Array(20);
for(let i=0; i&lt;20; i++) {
  world[i] = new Array(20);
  world[i].fill(new ColorBlock('#ff00ff'));
}

The function rendering each block as ColorBlock or ImageBlock:
function html_process_image_or_color_block(dom, block_instance) {
  const html_block = dom;
  const block = block_instance;
  const block_property = block.getProperty();
  switch (block.constructor.name) {
    case 'ImageBlock':
      const image_tag = document.createElement('img');
      image_tag.src = block_property;
      image_tag.classList.add('image-in-block');
      html_block.appendChild(image_tag);
      break;
    case 'ColorBlock':
      html_block.setAttribute('style', `background: ${block_property};`)
      break;
    default: break;
  }
  // return html_block;
}

And finally the render(world) function that uses the 20x20 Matrix and the above function:
function render(world) {
  const html_container = document.createElement('div');
  html_container.classList.add('container');
  for(let i=0; i&lt;20; i++) {
    
    //code for rendering first left most block
    const html_first_block = document.createElement('div');
    html_first_block.classList.add('block-first');
    const first_block = world[i][0];
    html_process_image_or_color_block(html_first_block, first_block);
    html_container.appendChild(html_first_block);
    
    //code for rendering all other blocks on its right
    for(let j=1; j&lt;20; j++) {
      const html_block = document.createElement('div');
      html_block.classList.add('block-lasts');
      const block = world[i][j];
      html_process_image_or_color_block(html_block, block);
      html_container.appendChild(html_block);
    }
  }
  document.body.innerHTML = '';
  document.body.appendChild(html_container);
}


render(world);

In my opinion the code is terrible :) and I appreciate all your time and effort!
Codepen
So I know there gotta be a better way but I found a satisfying one:
interface IBlock {
  getProperty() : string;
  render() : Object;
}

class ColorBlock {
  color: string;
  constructor(color: string) {
    this.color = color;
  }
  getProperty() : string {
    return this.color;
  }
  render(isFirstBlock: boolean) : Object/*Well it's an HTML dom object*/ {
    const tag = document.createElement('div');
    isFirstBlock? tag.classList.add('block-first') : tag.classList.add('block-lasts');
    tag.setAttribute('style', `background: ${this.color};`);
    return tag;
  }
}

class ImageBlock {
  url: string;
  constructor(url: string) {
    this.url = url;
  }
  getProperty() : string {
    return this.url;
  }
  render(isFirstBlock: boolean) : Object/*Well it's an HTML dom object*/ {
    const tag = document.createElement('div');
    isFirstBlock? tag.classList.add('block-first') : tag.classList.add('block-lasts');
    const image_tag = document.createElement('img');
    image_tag.src = this.url;
    image_tag.classList.add('image-block');
    tag.appendChild(image_tag);
    return tag;
  }
}

const global_x = 10;
const global_y = 10;

const world = new Array&lt;Array&lt;IBlock&gt;&gt;(global_x);

const default_ColorBlock = new ColorBlock('#ff00ff');

for(let i=0; i&lt;global_x; i++) {
  world[i] = new Array&lt;IBlock&gt;(global_y);
  world[i].fill(default_ColorBlock);
}

function render(world: Array&lt;Array&lt;IBlock&gt;&gt;) {
  const html_container = document.createElement('div');
  for(let i=0; i&lt;global_x; i++) {
    html_container.appendChild(world[i][0].render(true));
    for(let j=0; j&lt;global_y; j++) {
      html_container.appendChild(world[i][j].render(false));
    }
  }
  document.body.innerHTML = '';
  document.body.appendChild(html_container);
}

render(world);

CSS being:
:root {
  --global-width: 20px;
  --global-height: 20px;
}

.block-first, .block-lasts {
  width: var(--global-width);
  height: var(--global-height);
  border-radius: 50%;
  float: left;
}

.block-first {
  clear: both;
}

.image-block {
  width: var(--global-width);
  height: var(--global-height);
}

And no HTML outside of javascript (typescript) .