TL;DR: If you're using CUSTOM_ELEMENTS_SCHEMA ALWAYS create a module that imports your Web Components and wraps them into a real Angular component. Then, use that module in your other module that MUST NOT use CUSTOM_ELEMENTS_SCHEMA. Read on, if you're interested, why.

If you're using Angular together with Web Components, you need to add CUSTOM_ELEMENTS_SCHEMA to your module import, like this:

@NgModule({
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class MyModule {}

But, you're like to use it the wrong way. Using CUSTOM_ELEMENTS_SCHEMA opts out of a lot of useful Angular template checking features.

Imagine the following component and a module without CUSTOM_ELEMENTS_SCHEMA:

@Component({ 
  selector: 'my-component', 
  template: '',
 })
export class MyComponent {}

@NgModule({
  declarations: [MyComponent],
})
export class MyModule {}

Now imagine using that component somewhere like:

<my-component [thisDoesNotExist]="true"></my-component>

Using it in this way will make the Angular compiler throw an error, that thisDoesNotExist is not a known property of my-component. That's absolutely correct and the behavior we want to have!

If you now use CUSTOM_ELEMENTS_SCHEMA you will NOT get any error anymore. You can set any attribute or output, if it exists or not, Angular won't check that for you. You can also write any custom HTML tag, even if it does not exists, nobody will tell you anymore. It's easily to introduce bugs this way.

Solution

There's an easy solution for that: Wrap all your Web Components with Angular Components and declare those Angular Components in their own module using CUSTOM_ELEMENTS_SCHEMA. Then, import that wrapper module into your application, thtat MUST NOT use CUSTOM_ELEMENTS_SCHEMA. You get back all the template checking inside your Angular application, and you have turned it off for only one module, where that makes sense.

// Web Components Wrapper module
@Component({
  selector: 'my-web-component-wrapper',
  template: '<my-web-component [existingAttribute]="existingAttribute"></my-web-component>
})
export class MyWebComponentWrapper {
  @Input() existingAttribute: string;
}

@NgModule({
	declarations: [MyWebComponentWrapper],
    exports: [MyWebComponentWrapper],
    schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class WrapperModule {}

// Your real App module

@Component({
  selector: 'app-root',
  template: '<my-web-component-wrapper [existingAttribute]="'such wow!'"</my-web-component-wrapper>'
})
export class AppComponent {}

@NgModule({
	declarations: [AppComponent],
    imports: [WrapperModule]
})
export class AppModule {}

That's safe and sound.