You can get to filter by a dynamic column, as in no hardcoded column name, doing the following:
// On input focus: setup filterPredicate to only filter by input column
setupFilter(column: string) {
  this.dataSource.filterPredicate = (d: TableDataSourceType, filter: string) => {
    const textToSearch = d[column] && d[column].toLowerCase() || '';
    return textToSearch.indexOf(filter) !== -1;
  };
}
applyFilter(filterValue: string) {
  this.dataSource.filter = filterValue.trim().toLowerCase();
}
In the template you can have something like this:
<ng-container matColumnDef="item-filter">
  <th mat-header-cell *matHeaderCellDef>
    <input (keyup)="applyFilter($event.target.value)" (focus)="setupFilter('name')" />
  </th>
</ng-container>
Or a more complex example, dynamically create a header row with per-column filtering:
<table mat-table [dataSource]="dataSource">
   <ng-container *ngFor="let filterCol of ['names', 'age', 'address']">
     <ng-container matColumnDef="filterCol">
       <th mat-header-cell *matHeaderCellDef>
         <input (keyup)="applyFilter($event.target.value)" (focus)="setupFilter(filterCol)"/>
       </th>
     </ng-container>
   </ng-container>
   <tr mat-header-row *matHeaderRowDef="['names', 'age', 'address']"></tr>
</table>
Be aware that you cannot have multiple header rows with the same keys, so this will not work:
<tr mat-header-row *matHeaderRowDef="['names', 'age', 'address']"></tr>
<tr mat-header-row *matHeaderRowDef="['names', 'age', 'address']"></tr>